{***************************************************************
    SpyGestion  Copyright (C) 2008 Christophe KOALI <nature2gas@gmail.com>
    
    This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.
    
    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.
    
    You should have received a copy of the GNU General Public License
    along with this program.  If not, see <http://www.gnu.org/licenses/>.
    
****************************************************************}
unit modParsingClass;

interface

uses Classes, SysUtils, modBaseType, modCore, modCoreRecu,
     sHTMLFonctions,  modClassElements,
     modLinkOtherPlanet,
     modStatsPlayers,
     modGalaxiePlanetes,
     ESBDates,
     
     modFlotteVaisseauxChoix,
     modMessagesList,
     modFlotteEnVoyage,

     {$IFDEF FORUM_PARSING}
        modMemberList,
     {$ENDIF}

     modLanguageParsing,
     modBaseRessources,

     modApercuMsg,
     Windows,
     sFonctionsChaines, LibXmlParser, LibXmlComps;

     
const
    // Accesskey
    PG_MENU_Apercu          = 'u';
    PG_MENU_Batiments       = 'b';
    PG_MENU_Ressources      = 'r';
    PG_MENU_Recherche       = 'h';
    PG_MENU_ChantierSpatial = 's';
    PG_MENU_Flotte          = 'l';
    PG_MENU_Technologie     = 't';
    PG_MENU_Galaxie         = 'x';
    PG_MENU_Defense         = 'd';


    CNT_MIN_PAGESIZEFILE_FOR_SESSIONEXP_CHECK = 1600;


    LANG_PLANET_PARSING_ADD_INVALID     = ' (invalid language file)';

const
    // Identifier comme own flotte:
    APERCU_SPAN_CLASS_OWN_TRANSPORT        = 'flight owntransport';
    APERCU_SPAN_CLASS_OWN_TRANSPORT_RETOUR = 'return owntransport';

    APERCU_SPAN_CLASS_OWN_STATIONNER         = 'flight owndeploy';
    APERCU_SPAN_CLASS_OWN_STATIONNER_RETOUR  = 'return owndeploy';


    APERCU_SPAN_CLASS_OWN_RECYCLAGE        = 'flight ownharvest';
    APERCU_SPAN_CLASS_OWN_RECYCLAGE_RETOUR = 'return ownharvest';

    APERCU_SPAN_CLASS_OWN_ESPIONAGE        = 'flight ownespionage';
    APERCU_SPAN_CLASS_OWN_ESPIONAGE_RETOUR = 'return ownespionage';

    APERCU_SPAN_CLASS_OWN_ATTAQUE        = 'flight ownattack';
    APERCU_SPAN_CLASS_OWN_ATTAQUE_RETOUR = 'return ownattack';

    APERCU_SPAN_CLASS_OWN_COLONISATION = 'flight owncolony';
    APERCU_SPAN_CLASS_OWN_COLONISATION_RETOUR = 'return owncolony';




    // Flotte ennemi mechante:
    APERCU_SPAN_CLASS_ENNEMI_ATTACK              = 'flight attack';
    APERCU_SPAN_CLASS_ENNEMI_SPYING              = 'flight espionage';

    APERCU_SPAN_CLASS_ENNEMI_ATTACK_GROUP        = 'flight federation';


    // Flotte ennemi pacifique:
    APERCU_SPAN_CLASS_ENNEMI_TRANSPORT_PACIFIQUE = 'flight transport';







(*
.owntransport /*transport aller*/
.owntransport.return /*transport retour*/
.ownattack /*attaque aller*/
.ownattack.return /*attaque retour*/
.ownharvest /*xploiter aller*/
.ownharvest.return /*exploiter retour*/
.owndeploy /*stationner aller*/
.owndeploy.return /*stationner retour*/
.owncolony /*colonisation aller*/
.owncolony.return /*colonisation retour*/
.ownespionage /*espionnage aller*/
.ownespionage.return /*espionnage retour*/
.espionage /*espionnage subit*/
.attack /*attaque venant d'une personne*/
.transport /*transport venant d'une autre personne*/
*)

const
    MAX_UNIVERS = 20;

    CLASSTYPE_UNDEFINED       = 0;

(* Pour savoir si la class 'élément' est l'un de ces 4 type, on utilise
   la propriété design
    CLASSTYPE_BATIMENT        = 1;
    CLASSTYPE_RECHERCHE       = 2;
    CLASSTYPE_CHANTIERSPATIAL = 3;
    CLASSTYPE_DEFENSE         = 4;
*)

    CLASSTYPE_APPERCU         = 10;
    CLASSTYPE_RESSOURCE       = 11;
    CLASSTYPE_ELEMENTS        = 12;
    CLASSTYPE_FLOTTE1         = 13;

type
    //TUniversServeurHost = array[1..MAX_UNIVERS] of string[64];

    TParsingBase = class(TObject)
    private
        FScanner: TEasyXmlScanner;
        FScannerCreated: boolean;

        FURLOfThisPage: string;
        FError        : boolean;

        FTypeClass    : integer;

        // Protective Critical Section object
        FReadWriteCS: TRTLCriticalSection;


        {$IFDEF DEBUG}
           // informations de débogage
           FDebugProc: TsfcProcStatus;
        {$ENDIF}


    protected
        procedure ScanOnStartTag(Sender: TObject; TagName: string; Attributes: TAttrList); virtual; abstract;
        procedure ScanOnEndTag(Sender: TObject; TagName: string);  virtual; abstract;
        procedure ScanOnContent(Sender: TObject; Content: string); virtual; abstract;

        procedure SetDebugProc(Value: TsfcProcStatus); virtual;

        procedure DoDebug(const Msg: string);

    public
        // virtual car les classes descendent auront besoin de la surchargé
        // pour définir les liens complets des URL trouvé dans la page web
        procedure SetURLOfThisPage(Valeur: string); virtual;

        
        {$IFDEF DEBUG}
           property DebugProc: TsfcProcStatus read FDebugProc write SetDebugProc;
        {$ENDIF}

        property ClassTypeParsing: integer      read FTypeClass;
        property URLOfThisPage: string          read FURLOfThisPage write SetURLOfThisPage;
        property Scanneur     : TEasyXmlScanner read FScanner;
        property GetError     : boolean         read FError;

        // Parseur présent obligatoirement dans chaque page web
        function ParseBuffer(const Tampon: string): boolean; virtual;

        procedure Lock;
        procedure Unlock;

        constructor Create(Scanner: TEasyXmlScanner); virtual;
        destructor Destroy; override; 
    end;


    TParsingDebutDocumentMineraiAndPlanet = class(TObject)
    private
       FScanneur        : TEasyXmlScanner;

       // Lien de changement vers les autres planètes
       FOtherPlanetLink : TCollectionLinkOtherPlanete;


       FCurrentRessource: TOGRessourceAll;
       FCurrentPlanete  : TPlanetLocation;
       FCurrentPlaneteNom: string;

       // TODO: faire un tableau de planète disponible (de TPlanetLinkInfo)

       // Evènement pour restaurer les pointeurs d'origine
       FOnFinTravail : TNotifyEvent;
       FError : boolean;

       FInSelect : boolean;
       FInOption : integer;

       FCheckCondition: integer;

       FCurrLigne: integer;
       FCurrColonne: integer;

       FWitchLigneIsGood: integer;
       FWitchColonneIsGood: integer;
       FTamponForEnergie: string;
       FTamponDejaTraite: boolean;

       FExistOfficier: boolean;
       FExistCommandant: boolean;
       FCheckingOfficierDone: boolean;


       // avec la v76, il y a des balises entre les balises options
       // cela empêche d'avoir le nom de la planete de les coordonnées en meme temps
       // c'est un avantage, car on a d'un coté le nom de la planète, de l'autre les coordonnées
       // mais cela ne correspond pas au système actuel
       // au lieu de modifier et de chercher à savoir dans quelle sous balise on est,
       // on place tous dans un tampon et on utilise la méthode habituelle d'analyse
       FTamponForOption: string;

       FLastLinkPlaneteInfo: TLinkOtherPlanete;


       FExistHTML: boolean;
       FExistBODY: boolean;

        {$IFDEF DEBUG}
           // informations de débogage
           FDebugProc: TsfcProcStatus;
        {$ENDIF}

       procedure TraitementTamponEnergie;

       function GetPlaneteStr: string;

       function IsValidHeader: boolean;


       procedure OnOptionData(Content: string);

       procedure DoDebugMinerai(const Msg: string);

    public
       property ExistOfficier: boolean  read FExistOfficier;
       property ExistCommandant: boolean  read FExistCommandant;

       property Planete     : TPlanetLocation  read FCurrentPlanete;
       property PlaneteStr  : string           read GetPlaneteStr;
       property PlaneteNom  : string           read FCurrentPlaneteNom;
       
       property CurrRessource: TOGRessourceAll read FCurrentRessource;

       property OnFinTravail: TNotifyEvent read FOnFinTravail write FOnFinTravail;

       // Pour accéder aux liens des autres planètes
       property AutrePlanete : TCollectionLinkOtherPlanete read FOtherPlanetLink;


       function IsValidPage: boolean;

       // en public
       procedure ScanOnStartTag(Sender: TObject; TagName: string; Attributes: TAttrList);
       procedure ScanOnEndTag(Sender: TObject; TagName: string);
       procedure ScanOnContent(Sender: TObject; Content: string);

       procedure Prepare;
       constructor Create(Scanneur: TEasyXmlScanner);
       destructor Destroy; override;

        {$IFDEF DEBUG}
           property DebugProcMinerai: TsfcProcStatus read FDebugProc write FDebugProc;
        {$ENDIF}
    end;




    /////////////////////////////////////////////////////////
    // Analyse la page qui demande le login, pour remplir tout
    // les champs, et connaitre le serveur de l'univers
    // Note: Bien que la plupart des données à poster sont
    // déjà connue, même le timestamp peut être "deviner", il
    // est quand même préférable d'analyser la page
    TParsingLogInPage = class(TParsingBase)
    private
       // Page: http://xxxxxx.de/portal/?lang=fr
     //  FScanner: TEasyXmlScanner;
     //  FError : boolean;

       // Liste des url de serveur
       //FUniversServer : TUniversServeurHost;

       FLogin   : string;
       FPassword: string;
       FUnivers : integer;

       // Chaque valeur caché est ajouté dans cette chaine
       //FHiddenValue: string;

       // Données à poster
       FDataToPost: string;

       // URL où poster les données
       // le &x=7&y=8
       // correspondent en fait à la position où l'on
       // a cliqué sur l'image
       FURLToPost : string;
       FServeurUniv: string;


       // nom du bouton image sur lequel on click pour soumettre les données
       FInputImageButton: string;


       //////////////////////////////////
       // Pour la gestion du scanneur
       FInForm : boolean;
       FLastOptionValue: string;
       FInOption: boolean;


       // pour les univers spéciaux (l'univers béta en particulier)
       FNoMouseClick : boolean;
       FSpecialLoginWithValidAction: boolean;

       procedure ScanOnStartTag(Sender: TObject; TagName: string; Attributes: TAttrList); override;
       procedure ScanOnEndTag(Sender: TObject; TagName: string);  override;
       procedure ScanOnContent(Sender: TObject; Content: string); override;
    public
    //   property GetError : boolean read FError;
       property NoMouseClick: boolean read FNoMouseClick write FNoMouseClick;
       property SpecialLoginWithValidAction: boolean read FSpecialLoginWithValidAction write FSpecialLoginWithValidAction;
       

       property Username : string  read FLogin    write FLogin;
       property Password : string  read FPassword write FPassword;
       property Univers  : integer read FUnivers  write FUnivers;

       property DataToPost: string read FDataToPost;
       property URLToPost : string read FURLToPost;

       function ParseBuffer(const Tampon: string): boolean; override;

       constructor Create(Scanner: TEasyXmlScanner); override;
       destructor Destroy; override;
    end;


    /////////////////////////////////////////
    // analyse l'url de redirection
    // il l'a faut obligatoirement car elle contient le numéro de session
    // Même si il peut être deviner, il vaut mieux analyser la page
    TParsingAfterLogInPage = class(TObject)
    private
       FScanner: TEasyXmlScanner;
       FError : boolean;

       FURLRedirect: string;

       procedure ScanOnStartTag(Sender: TObject; TagName: string; Attributes: TAttrList);

    public
       property BasicURLRedirection: string read FURLRedirect;
       function ParseBuffer(const Tampon: string): boolean;

       constructor Create;
       destructor Destroy; override;
    end;


    /////////////////////////////////////////
    // Analyse la page qui définit les frames
    // Même si les liens sont déjà connue, il manque les
    // numéro de session (peut-être devinable ?)
    // Dans tout les cas, il vaut mieux analyser la page
    TParsingFrameSet = class(TObject)
    private
       FScanner: TEasyXmlScanner;
       FError : boolean;
       // Pour simplifier le lien referer
       FURLOfThisFrame: string;

       FFrameURLLeft : string;
       FFrameURLRight: string;
       FFrameRightName: string;

       procedure ScanOnStartTag(Sender: TObject; TagName: string; Attributes: TAttrList);

    public
       property URLOfThisFrame   : string  read FURLOfThisFrame write FURLOfThisFrame;
       property BasicURLFrameLeft: string read FFrameURLLeft;
       property BasicURLFrameRight: string read FFrameURLRight;


       function ParseBuffer(const Tampon: string): boolean;

       constructor Create;
       destructor Destroy; override;
    end;

const
    CNT_MENU_APPERCU    = 1;
    CNT_MENU_BATIMENTS  = 2;
    CNT_MENU_RESSOURCES = 3;
    CNT_MENU_RECHERCHES = 4;
    CNT_MENU_CHANTIERSPATIAL = 5;
    CNT_MENU_FLOTTE     = 6;
    CNT_MENU_DEFENSE    = 7;
    CNT_MENU_MESSAGES   = 8;
    CNT_MENU_STATISTIQUES = 9;

    CNT_MENU_GALAXIE    = 10;


    CNT_MENU_ARRAY_ID_START = CNT_MENU_APPERCU;
    CNT_MENU_ARRAY_ID_END   = CNT_MENU_GALAXIE;

type

    TLinkMenu = array[CNT_MENU_ARRAY_ID_START..CNT_MENU_ARRAY_ID_END] of string;

    /////////////////////////////////////////////
    // Parsing du menu à gauche
    TParsingMenuLeft = class(TObject)
    private
       FScanner: TEasyXmlScanner;
       FError : boolean;

       // URL de la Frame en cours pour faciliter le rafraichissement de celle-ci
       FURLOfThisFrame: string;

       FLinks      : TLinkMenu;
       FLinksBackup: TLinkMenu;

       FInLink   : boolean;
       FLaskLink : string;

       FIsCompteCommandant: boolean;

       // Depuis la 0.76d le menu ne se refresh plus
       FDelayRefresh: integer;
       FURLToDownloadAsIgnore: TStringList;

       procedure ScanOnStartTag(Sender: TObject; TagName: string; Attributes: TAttrList);
       procedure ScanOnEndTag(Sender: TObject; TagName: string);
       procedure ScanOnContent(Sender: TObject; Content: string);

       function GetNbLinkFound: integer;

    public
       // en seconde
       property DelayRefresh: integer read FDelayRefresh;
       property URLToDownloadAsIgnore: TStringList read FURLToDownloadAsIgnore;


       procedure RestaureBackup;
       procedure SaveToBackup;

       property IsCompteCommandant: boolean read FIsCompteCommandant;

       procedure SetFullURLFromBase(const BaseLink: string);

       property URLOfThisFrame : string read FURLOfThisFrame write FURLOfThisFrame;
       
       function GetLink(IdLink: integer): string;

       function ParseBuffer(const Tampon: string): boolean;

       constructor Create;
       destructor Destroy; override;
    end;





type


    TParsingBaseGamePage = class(TParsingBase)
    private
       // Chaque page a une en tête
       FHeaderParser: TParsingDebutDocumentMineraiAndPlanet;


    protected

       function GetPlanetStr: string;
       function GetRessources: TOGRessourceAll;
       function GetIsValidHeader: boolean;


       procedure SetDebugProc(Value: TsfcProcStatus); override;

    public
       property cHeader : TParsingDebutDocumentMineraiAndPlanet read FHeaderParser;
       property PlaneteStr  : string          read GetPlanetStr;
       property Ressources  : TOGRessourceAll read GetRessources;
       property IsValidHeader: boolean        read GetIsValidHeader;


       // On implémente une partie de cette fonction, pour gérer l'header
       // et CHARGE le tampon, sans pour autant lancer l'exécution
       function ParseBuffer(const Tampon: string): boolean; virtual;

       procedure SetURLOfThisPage(Valeur: string); virtual;

       // A partir du moment où il existe une entête, il existe obligatoirement
       // une procédure de Callback
       procedure OnFinHeader(Sender: TObject);

       constructor Create(Scanner: TEasyXmlScanner); override;
       destructor Destroy; override;
    end;



    /////////////////////////////////////////////////////////
    // Analyse la page des ressources
    TParsingPageRessource = class(TParsingBaseGamePage)
    private
       FDontFreeTList: boolean;

       // Liste des éléments du tableau
       FRes : TList;

       // Adresse du formulaire si l'on veut modifier les données
       // La méthode est normalement "post"
       FFormAction: string;

       // pour le bouton valider:
       // car les données postées ressemble à:
       // last1=100&last2=100&last3=100&last4=100&last12=100&action=Calculer
       // quand on met tout à 100%
       FSubmitPostAdd: string;

       FInForm: boolean;
       FInTable: boolean;
       FCurrTableLigne: integer;
       FCurrTableColone: integer;
       FInSelect: boolean;
       FItemsTerminated: boolean;


       FCurrElement: POGResUsed;

       procedure ScanOnStartTag(Sender: TObject; TagName: string; Attributes: TAttrList); override;
       procedure ScanOnEndTag(Sender: TObject; TagName: string);  override;
       procedure ScanOnContent(Sender: TObject; Content: string); override;

       procedure InitPointeur;
       //procedure SetURLOfThisPage(Valeur: string); override;
       
    public
       property FormAction       : string  read FFormAction;
       property SubmitPostAdd    : string  read FSubmitPostAdd;
       
       property DontFreePointeur : boolean read FDontFreeTList write FDontFreeTList;

       property Valeurs: TList read FRes;
       function ParseBuffer(const Tampon: string): boolean; override;

       procedure SetURLOfThisPage(Valeur: string); override;


       constructor Create(Scanner: TEasyXmlScanner); override;
       destructor Destroy; override;
    end;


const
    CNT_STATSPLAYER_PGTYPE_GENERAL = 1;
    CNT_STATSPLAYER_PGTYPE_FLOTTES = 2;
    CNT_STATSPLAYER_PGTYPE_RECHERCHE = 3;


type

    TStatsTypeX = (stoPointsX, stoFlottesX, stoRechercheX);

    TParsingPlayerStats = class(TParsingBaseGamePage)
    private
       FStatsList: TListStatsPlayerSP;

       FLinkSwitchPointsGeneral: string;
       FLinkSwitchPointsFlottes: string;
       FLinkSwitchPointsRecherche: string;
       FLinkSwichtPointsSelected: integer;

       // indice 1: Top 100  ; Indice 2: Top 200, etc...
       // contient les données à poster
       FLinkSwitchTop : array[1..15] of string;

       // format à utiliser
       FFormatToUse: string;


       FTypeStats : TStatsTypeX;

       FDontAddToList: boolean;

       // <rank>
       //FDataToPost: string;

       // Indice de la page en cours
       FLinkSwitchTopSelected: integer;

       // Sert pour le parsing car on n'utilise pas les données de OnContent
       FLinkCurrPos: integer;



       FInSelect: integer;

       FInTable: boolean;
       FCurrTableLigne: integer;
       FCurrTableColonne: integer;

       FCanWaitForTable: boolean;
       FInForm : boolean;

       // Joueur en cours
       FCurrentPlayer: TPlayerStats;

       procedure ScanOnStartTag(Sender: TObject; TagName: string; Attributes: TAttrList); override;
       procedure ScanOnEndTag(Sender: TObject; TagName: string);  override;
       procedure ScanOnContent(Sender: TObject; Content: string); override;


    protected
       procedure InitPlayer;

    public
       property TypeStats : TStatsTypeX read FTypeStats write FTypeStats;

       property Stats: TListStatsPlayerSP read FStatsList;
       property DontAddToList: boolean read FDontAddToList write FDontAddToList;

       function GetLinkTop(Index: integer): string;
       property LienSwitchPointsGeneral: string read FLinkSwitchPointsGeneral;
       property LienSwitchPointsFlottes: string read FLinkSwitchPointsFlottes;
       property LienSwitchPointsRecherche: string read FLinkSwitchPointsRecherche;
       property LienSwitchPointsSelected: integer read FLinkSwichtPointsSelected;

       procedure SetURLOfThisPage(Valeur: string); override;


       function ParseBuffer(const Tampon: string): boolean; override;

       constructor Create(Scanner: TEasyXmlScanner); override;
       destructor Destroy; override;
    end;


    ///////////////////////////////////////////////////////////
    // Parsing de la page Batiments, Recherche, Chantier Spatial, Défense
    // Les deux derniers utilisent un formulaire pour permettre de spécifier
    // combien d'élément on veut en construire
    TParsingBatiment = class(TParsingBaseGamePage)
    private
       FFormMode: boolean;

       // ceci determine ce que l'on doit faire des pointeurs actuels de la liste
       FDontFreeTList: boolean;

       // Définit si on ne peut pas construire d'élément parce qu'il y a
       // déjà un élément en cours de construction
       // Définit à partir de la balise script
       // Car de toute façon, tout les élément auront link à ''
       FCannotBuild: boolean;


       // Liste des éléments
       FElementsList : TListElements;

       // Adresse du formulaire si c'est une page du genre
       // 'flotte' ou 'défense'
       FFormAction: string;

       FCurrElement: POGItemCost;


       //FLevelAnalyse: integer;
   //    FCanGoNextLevel: boolean;

       FInForm : boolean;
       FInTable: boolean;
       FInLink : boolean;
       FInLinkInfoElementStr: boolean;
       FNextContentIsMaybeNiveau: boolean;
       FNextMaybeScriptDurationConstruction : boolean;

       FInScript: boolean;

      // FInSelect: boolean;
      // FInOption: integer;   // 0=non 1=oui 2=oui et option sélectionnée


       // Permet d'extraire les données seulement à la fin du <br>
       // sans tenir compte des balises <b>
       FInRessourceNeed: boolean;
       FRessourceNeedStr: string;

       FCurrTableLigne: integer;
       FCurrTableColonne: integer;


       FNbElementTrouve: integer;



       procedure ScanOnStartTag(Sender: TObject; TagName: string; Attributes: TAttrList); override;
       procedure ScanOnEndTag(Sender: TObject; TagName: string);  override;
       procedure ScanOnContent(Sender: TObject; Content: string); override;
    protected
       procedure InitPointeur;

    public
       GidType: TTypeGID;

       property NbElementTrouve: integer      read FNbElementTrouve;

       property DontFreePointeur : boolean    read FDontFreeTList write FDontFreeTList;


       property Valeurs     : TListElements           read FElementsList;
       property CannotBuild : boolean         read FCannotBuild;


       property FormAction : string read FFormAction;

       function ParseBuffer(const Tampon: string): boolean; override;
       procedure FreePointeurAndClear;

       constructor Create(Scanner: TEasyXmlScanner); override;
       destructor Destroy; override;
    end;

    TParsingAppercu = class(TParsingBaseGamePage)
    private
       FCasesOccupees: integer;
       FCasesTotal   : integer;
       FPoints      : integer;
       FClassementPosition: integer;
       FClassementTotalPlayers: integer;
       FCurrNomPlantet: string;
       FCurrNomJoueur: string;
       FDateServeur: int64;
       FIsLune: boolean;

       FCurrAttackGroup: integer;

       FMessageList: TCollectionAppMessage;


       FInDataUtile: boolean;
       FInTable: integer;
       FWhatIsNextContent: integer;
       FTamponTraitement: string;

       FTable1Ligne  : integer;
       FTable1Colonne: integer;
       FTable1ColonneSpan: integer;
       FInFont : boolean;


       FThisLigneIsFlotte: boolean;
       FContentPos: integer;

       FAppFlotteMsg: TAppMessage;
       FOverrideSpanClassOrdre: boolean;
       FOverrideSpanClassDirection: boolean;

       FUseSpanClass_AND_MsgGame_If_Fail: boolean;
       FNotFromSpanChecked: boolean;

       FTypeMsg : integer;
       FTitleBaliseA: string;
       FSpanClass   : string;
       FAClass : string;


       // Version 0.76
       // Modification dans le jeu: Les coordonnées sont encadrées d'une balise <A>
       // c'est à dire d'un lien permettant de voir le système solaire correspondant
       //
       // Pour faire une adaptaton très simple, on bufferise les données
       FFlotteBuffer: string;



   //    FTable2Ligne  : integer;  // update: on ignore les tableaux inclu dans le tableau qui nous est utile
   //    FTable2Colonne: integer;


       procedure ScanOnStartTag(Sender: TObject; TagName: string; Attributes: TAttrList); override;
       procedure ScanOnEndTag(Sender: TObject; TagName: string);  override;
       procedure ScanOnContent(Sender: TObject; Content: string); override;

       procedure ExtractPointClassement(Tampon: string);
       procedure ExtractCasesDiametre;

       procedure InitMsgFlotte(bDoNotResetDateEtDuree: boolean = true);
       
       //procedure GestionMsgAutreJoueur(Content: string);
       function GestionMsgFlotteAutreJoueur(Content: string): boolean;
       function GestionMsgFlotteLaNotre(Content: string): boolean;
    public
       property MsgList : TCollectionAppMessage read FMessageList;
       property CasesOccupees: integer       read FCasesOccupees  write FCasesOccupees;
       property CasesTotales : integer       read FCasesTotal     write FCasesTotal;
       property Points : integer             read FPoints         write FPoints;

       property ClassementPosition: integer  read FClassementPosition      write FClassementPosition;
       property ClassementNbJoueurs: integer read FClassementTotalPlayers  write FClassementTotalPlayers;

       property ServeurDate: int64 read FDateServeur;

       property NomPlanete: string   read FCurrNomPlantet  write FCurrNomPlantet;
       property NomJoueur: string    read FCurrNomJoueur   write FCurrNomJoueur;

       function ParseBuffer(const Tampon: string): boolean; override;

       constructor Create(Scanner: TEasyXmlScanner); override;
       destructor Destroy; override;
    end;


const
    // Valeur possible pour FTypeMsg de Apercu
    CNT_FLOTTE_TYPEMSG_TRANSPORTPLANETE_ALLER = 1;
    CNT_FLOTTE_TYPEMSG_TRANSPORTALLIE_ALLER   = 2;
    CNT_FLOTTE_TYPEMSG_ENNEMI_ALLER           = 3;



type


    ////////////////////////////////////////////////////////////////////
    // La page galaxie ne possède pas d'entête de ressource
    // Les types de la galaxie sont definit dans modGalaxiePlanetes
    TParsingGalaxie = class(TParsingBase)
    private
        // Galaxie, Systeme solaire et SessionKey de la page parsée
        FGalaxie: integer;
        FSystemSolaire: integer;
        FSessionKey: string;



        // Liste des planetes du systeme solaire
        FListPlanete: TListGalaxiePlaneteSP;


        FInScript: boolean;
        FScriptBaliseNum: integer;
        //FAllowOneError: boolean;

        // Lors du deuxieme parsing
        //FInTableauGalaxie: boolean;

        FInTable: boolean;
        FTableLigne: integer;
        FTableColonne: integer;

        FInFont: boolean;
        FInLink: boolean;


        // Pour savoir si on est dans les paranthèses pour idenfier les flags inactif/vacances/noob
        FInTagOption: boolean;

        FStateColPlanete: integer;

        FCurrentPlanete: TGalaxiePlanete;

        // tampon pour extraire correctement l interieur des balises scripts
        FFullContent: string;
        FFontColor: string;

        // Tout comme pour les stats, cela évite d'ajouter la première page parsée
        // car les pointeurs seront "perdu" (jamais libéré)
        FDontAddPointeur: boolean;


        procedure ScanOnStartTag(Sender: TObject; TagName: string; Attributes: TAttrList); override;
        procedure ScanOnEndTag(Sender: TObject; TagName: string);  override;
        procedure ScanOnContent(Sender: TObject; Content: string); override;

        // les deux premiers balises peuvent etre identifie avec le parseur
        // et on stop le parseur a la fin de l extraction de la seconde balise script utile
        //procedure TraitementPremiereBaliseScript;
        //procedure TraitementSecondeBaliseScript;

        // Remet a zero que les champs variable
        procedure InitPlanete;

        procedure ExtractLuneInfoFromStr(s: string);
        procedure ExtractRuinesInfoFromStr(s: string);

        //procedure TraitementFlags(sFlags: string);
        procedure CheckAndAjoutCurrent;
    public
       property Galaxie: integer       read FGalaxie;
       property SystemSolaire: integer read FSystemSolaire;
       property SessionKey: string    read FSessionKey;

       property DontAddPointeur : boolean read FDontAddPointeur write FDontAddPointeur;


       property ListPlanete: TListGalaxiePlaneteSP read FListPlanete;
       
       function ParseBuffer(const Tampon: string): boolean; override;

       constructor Create(Scanner: TEasyXmlScanner); override;
       destructor Destroy; override;

    end;

(*
    TFlotteSelectionInWhat = (fsiwNeant, fsiwListDesFlottes, fsiwVaisseauChoix);

    ////////////////////////////////////////////////////////////////////
    // Page flotte 1, sélection des vaisseaux à envoyer
    TParsingFlotte1_ChoixVaisseaux = class(TParsingBaseGamePage)
    private
        // Flotte maximale possible
        FFlotteMax : integer;
        FFlotteUsed: integer;

        FFlotteAmiralDeFlotte: boolean;


        // Attention: Il existe d'autre formulaire pour le retour de flotte
        FURLToPostChoixVaisseaux: string;

        FLastABaliseTitle: string;

        FVaisseauxList: TCollectionVaisseauSelInfos;
        FFlotteList   : TCollectionFlotteListEnVoyage;

        FBoutonSubmitExist: boolean;

        FCurrentVaisseau: TVaisseauSelInfos;
        FCurrentFlotte  : TFlotteListEnVoyage;

        FInWhat: TFlotteSelectionInWhat;

        FCurrTableLigne  : integer;
        FCurrTableColonne: integer;

        FFormulaireCountHidden: integer;
        FFormulaireRetourFound: boolean;
        FInForm: boolean;
        
        procedure InitVaisseau;
        procedure InitFlotte;

        function IsValidVaisseau: boolean;
        function IsValidFlotte: boolean;

        procedure ScanOnStartTag(Sender: TObject; TagName: string; Attributes: TAttrList); override;
        procedure ScanOnEndTag(Sender: TObject; TagName: string);  override;
        procedure ScanOnContent(Sender: TObject; Content: string); override;

        procedure TraiteContentVaisseauxList(Content: string);
        procedure TraiteContentFlotteList(Content: string);

        procedure AddHidden(KeyName, Value: string);
        function GetKeyNameGID(KeyName: string; var KeySansLeGID: string): integer;

    public
       property URLToPost : string  read FURLToPostChoixVaisseaux write FURLToPostChoixVaisseaux;
       property FlotteMax : integer read FFlotteMax;
       property FlotteUsed: integer read FFlotteUsed;

       property VaisseauxList: TCollectionVaisseauSelInfos   read FVaisseauxList;
       property FlotteList   : TCollectionFlotteListEnVoyage read FFlotteList;

       function ParseBuffer(const Tampon: string): boolean; override;
       procedure SetURLOfThisPage(Valeur: string); override;


       constructor Create(Scanner: TEasyXmlScanner);  override;
       destructor Destroy; override;

    end;
*)


    
    ////////////////////////////////////////////////////////////////////
    // Page flotte 2, sélection de la destination et de la vitesse
    TParsingFlotte2_ChoixDestination = class(TParsingBaseGamePage)
    private
        FInForm: boolean;

        FDataToPost: string;
        FPageToPost: string;

        // Inutile et évident car la flotte part de la planète actuelle,
        // mais puisqu'il est présent dans les champs hidden, on le capture
        // Cela sert surtout pour le calcul du temps mis
        FPlaneteDepart: TPlanetLocation;

        // Devrait toujours être à 1, dans le cas contraire il faut déclencher une erreur
        // En réalité, dans l'univers béta les flottes vont 5 fois plus vite
        // et comme par hasard SpeedFactor est à 5
        // c'est probablement une variable interne au jeu, on ne déclenche plus d'erreur
        // mais on rend sa valeur disponible à l'extérieur de la classe
        FSpeedFactor: string;



        // Doit définir si c'est une lune ou pas à mon avis
        // <input name="thisplanettype" type="hidden" value="1" />

        procedure ScanOnStartTag(Sender: TObject; TagName: string; Attributes: TAttrList); override;
        procedure ScanOnEndTag(Sender: TObject; TagName: string);  override;
        procedure ScanOnContent(Sender: TObject; Content: string); override;

    public
       property DataToPost: string read FDataToPost;
       property PageToPost : string read FPageToPost;

       property SpeedFactor: string read FSpeedFactor;

       procedure SetURLOfThisPage(Valeur: string); override;
       function ParseBuffer(const Tampon: string): boolean; override;
    end;


    
    ////////////////////////////////////////////////////////////////////
    // Page flotte 3, sélection des ressources et de l'ordre
    TParsingFlotte3_OrdreEtRessources = class(TParsingBaseGamePage)
    private
        FInForm: boolean;
        FRadioDejaTraiter: boolean;

        FDataToPost: string;
        FPageToPost: string;
        FListOrdreDispo: TStringList;

        // Ressources actuelles
        FCurrentRessource: TOGRessourceAll;

        procedure ScanOnStartTag(Sender: TObject; TagName: string; Attributes: TAttrList); override;
        procedure ScanOnEndTag(Sender: TObject; TagName: string);  override;
        procedure ScanOnContent(Sender: TObject; Content: string); override;

    public
       property DataToPost: string read FDataToPost;
       property PageToPost : string read FPageToPost;

       function ExistThisOrdre(Ordre: string): boolean;
       function ExistOrdre: boolean;


       property CurrRessource: TOGRessourceAll read FCurrentRessource write FCurrentRessource;

       procedure SetURLOfThisPage(Valeur: string); override;
       function ParseBuffer(const Tampon: string): boolean; override;

       constructor Create(Scanner: TEasyXmlScanner); override;
       destructor Destroy; override;

    end;

    ////////////////////////////////////////////////////////////////////
    // Page flotte 4, confirmation d'envoi
    TParsingFlotte4_ContentNextIs = (pf4Neant, pf4Depart, pf4Arrivee, pf4Consomation, pf4Vitesse, pf4Distance);
    TParsingFlotte4_ConfirmationEnvoi = class(TParsingBaseGamePage)
    private

        FFlotteDepart : TPlanetLocation;
        FFlotteArrivee: TPlanetLocation;

        FFlotteConsomation: integer;
        FFlotteVitesse: integer;
        FFlotteDistance: integer;

        // Si la planète n'existe plus
        FPlaneteDestinationVide : boolean;

        // Si la planète a la protection des noob
        FPlaneteDestinationNoobProtect: boolean;
        FPlaneteIsInModeVacance : boolean;
        FPlaneteAdmin: boolean;
        FDeuteriumError: boolean;  // besoin de plus de deutérium

        // Quand il y a une erreur, un message global aux erreurs est aussi présent
        // cette variable indique si ce message global d'erreur existe
        FGeneralError: boolean;
        FBaliseFinHTMLTrouve: boolean;

        FInTable: boolean;
        FCurrTableLigne  : integer;
        FCurrTableColonne: integer;

        FNextContent: TParsingFlotte4_ContentNextIs;


        procedure ScanOnStartTag(Sender: TObject; TagName: string; Attributes: TAttrList); override;
        procedure ScanOnEndTag(Sender: TObject; TagName: string);  override;
        procedure ScanOnContent(Sender: TObject; Content: string); override;

        // Renvoi  FPlaneteDestinationVide or FPlaneteDestinationNoobProtect
        function GetPlaneteCantBeAccessible: boolean;
        
    public
        property PageWebBienDL: boolean         read FBaliseFinHTMLTrouve;

        property FlotteDepart : TPlanetLocation read FFlotteDepart;
        property FlotteArrivee: TPlanetLocation read FFlotteArrivee;

        property IsPlaneteVide: boolean     read FPlaneteDestinationVide;
        property IsPlaneteProtectNoob: boolean     read FPlaneteDestinationNoobProtect;
        property IsPlaneteModeVacance: boolean    read FPlaneteIsInModeVacance;

        property IsDeuteriumError: boolean read FDeuteriumError;

        // Définit si cette planète peut être accessible (c'est à dire que si
        // l'envoi à échoué par manque de deutérium, cette propriété sera à false)
        property IsPlaneteCantBeAccessible: boolean read GetPlaneteCantBeAccessible;

        property GeneralErreur: boolean read FGeneralError;


        // "A cause de la protection des noobs tu ne peux pas espionner cette planète!"

        property FlotteConsomation: integer read FFlotteConsomation;
        property FlotteVitesse: integer read FFlotteVitesse;
        property FlotteDistance: integer read FFlotteDistance;

        function ParseBuffer(const Tampon: string): boolean; override;
    end;


    TParsingMessagesList = class(TParsingBaseGamePage)
    private

        FPageToPost: string;

        FNbFormTag : integer;

        // Contient simplement: deletemessages=deleteallshown&messages=1
        // si on efface les messages montrés
        FDataToPost: string;


        FMessageList: TCollectionOGMessage;

        FInTable: integer;
        FCurrTableLigne  : integer;
        FCurrTableColonne: integer;

        FCurrMsg: TOGMessage;
        FThisLigneIsContent: integer;


        FIsInRapportCombat: boolean;


        FCurrBuffer: string;

        procedure InitMsg;
        function IsValidMsg: boolean;


        procedure ScanOnStartTag(Sender: TObject; TagName: string; Attributes: TAttrList); override;
        procedure ScanOnEndTag(Sender: TObject; TagName: string);  override;
        procedure ScanOnContent(Sender: TObject; Content: string); override;
    public
        property DataToPost : string read FDataToPost;
        property PageToPost : string read FPageToPost;

        property MessageList: TCollectionOGMessage read FMessageList;

        function ParseBuffer(const Tampon: string): boolean; override;

        procedure SetURLOfThisPage(Valeur: string); override;
        constructor Create(Scanner: TEasyXmlScanner); override;
        destructor Destroy; override;
    end;



    {$IFDEF FORUM_PARSING}


    TForumProfilNextIsWhat = (pnwNeant, pnwRegDate, pnwRank,
    pnwPosts, pwnLastActive1, pwnLastActive2, pwnLastPost, pwnLastPostWhen,
    pnwICQ, pnwAOL, pnwYahoo, pnwMSN, pnwEmail, pnwHomePage,
    pnwGender, pnwDateNaissance, pnwUnivers, pnwLocation,
    pnwInterest, pnwOccupation);


    TParsingForumProfil = class(TParsingBase)
    private
       FUID    : integer;
       FPseudo : string;

       FRegDate: int64;
       FRank   : string;
       FPosts  : integer;
       FLastPostDate: int64;
       FLastActive  : int64;
       FICQ    : string;
       FAOL    : string;
       FYahoo  : string;
       FMsn    : string;
       FEmail  : string;
       FHomepage: string;
       FGender : integer;
       FDateNaissance: string;
       FUnivers: string;
       FLocation: string;
       FInterests: string;
       FOccupation: string;

       FNomDeLaTable : string;

       FCurrTableLigne  : integer;
       FCurrTableColonne: integer;

       FPosition: integer;
       FNext: TForumProfilNextIsWhat;

       procedure ScanOnStartTag(Sender: TObject; TagName: string; Attributes: TAttrList); override;
       procedure ScanOnEndTag(Sender: TObject; TagName: string);  override;
       procedure ScanOnContent(Sender: TObject; Content: string); override;
    public
       property uID       : integer    read FUID;
       property uPseudo   : string     read FPseudo;
       property uRegDate  : int64      read FRegDate;
       property uRank     : string     read FRank;
       property uPosts    : integer    read FPosts;
       property uLastPostDate: int64   read FLastPostDate;
       property uLastActive  : int64   read FLastActive;
       property uICQ      : string     read FICQ;
       property uAOL      : string     read FAOL;
       property uYahoo    : string     read FYahoo;
       property uMsn      : string     read FMsn;
       property uEmail    : string     read FEmail;
       property uHomepage : string     read FHomepage;
       property uGender   : integer    read FGender;
       property uDateNaissance: string read FDateNaissance;
       property uUnivers  : string     read FUnivers;
       property uLocation : string     read FLocation;
       property uInterests: string     read FInterests;
       property uOccupation: string    read FOccupation;

       function GetSQLReq: string;

       property NomDeLaTable: string  read FNomDeLaTable write FNomDeLaTable;


       function IsValidProfil: boolean;
       procedure Init;

       function ParseBuffer(const Tampon: string): boolean; override;

       constructor Create(Scanner: TEasyXmlScanner); override;
       destructor Destroy; override;
    end;

    TParsingForumMemberList = class(TParsingBase)
    private
       FInDataUtile: boolean;
       
       FCurrTableLigne  : integer;
       FCurrTableColonne: integer;

       // Compteur pour savoir combien d'élément ont été ajouté
       FNbAddItem: integer;

       // Pour s'assurer que la page a été bien téléchargée
       FHtmlFinRencontre: boolean;

       FListItems: TCollectionMemberItemFromList;


       CurrItem: TMemberItemFromList;

       procedure ScanOnStartTag(Sender: TObject; TagName: string; Attributes: TAttrList); override;
       procedure ScanOnEndTag(Sender: TObject; TagName: string);  override;
       procedure ScanOnContent(Sender: TObject; Content: string); override;

       procedure InitItem;
       function IsValidItem: boolean;
       function GetToutEstOk: boolean;

    public
       property NbAddItem: integer read FNbAddItem;
       property ListItems: TCollectionMemberItemFromList read FListItems;
       property ToutEstOK: boolean read GetToutEstOk;

       function ParseBuffer(const Tampon: string): boolean; override;

       constructor Create(Scanner: TEasyXmlScanner); override;
       destructor Destroy; override;
    end;


    {$ENDIF}


    TParsingEcrireMessage = class(TParsingBaseGamePage)
    private
       FPostURL: string;
       FPostData: string;
       FDestinataireChamp: string;

       FInForm: boolean;

       
       procedure ScanOnStartTag(Sender: TObject; TagName: string; Attributes: TAttrList); override;
       procedure ScanOnEndTag(Sender: TObject; TagName: string);  override;
       procedure ScanOnContent(Sender: TObject; Content: string); override;


    public
       property PostURL: string read FPostURL;
       property PostData: string read FPostData;
       property Destinaire: string read FDestinataireChamp;

       function ParseBuffer(const Tampon: string): boolean; override;

       constructor Create(Scanner: TEasyXmlScanner); override;
       destructor Destroy; override;
    end;


    
const
    // Constantes pour le parsing de la page apercu
    CNT_NEXT_CONTENT_UNKNOW       = 0;
    CNT_NEXT_CONTENT_PLANETNAME   = 1;
    CNT_NEXT_CONTENT_PSEUDOJOUEUR = 2;
    CNT_NEXT_CONTENT_NEWMESSAGE   = 3;
    CNT_NEXT_CONTENT_POINTS       = 4;
    CNT_NEXT_CONTENT_IN_DIAMETRE  = 5;
    CNT_NEXT_CONTENT_IN_DIAMETRE_BUF  = 6;
    CNT_NEXT_CONTENT_SERVER_TIME   = 7;

    CNT_NEXT_CONTENT_POINTS_PLACE     = 10;
    CNT_NEXT_CONTENT_POINTS_NBPLAYERS = 11;

    CNT_FLOTTE2_IN_GALAXYCIBLE = '<<galaxy>>';
    CNT_FLOTTE2_IN_SYSTEMCIBLE = '<<system>>';
    CNT_FLOTTE2_IN_PLANETPOSCIBLE = '<<planetpos>>';
    CNT_FLOTTE2_IN_CIBLETYPE    = '<<cibletype>>';    // lune/ruines/planète voir plus bas pour les constantes de valeur
    CNT_FLOTTE2_IN_SPEEDRATIO   = '<<speedratio>>';   // de 1 à 10 (10=100% et 1=10%)

    CNT_FLOTTE2_VAL_CIBLETYPE_PLANETE = '1';
    CNT_FLOTTE2_VAL_CIBLETYPE_RUINES  = '2';
    CNT_FLOTTE2_VAL_CIBLETYPE_LUNE    = '3';


    CNT_ECRIRE_MSG_SUJET        = '<<sujet>>';
    CNT_ECRIRE_MSG_CONTENU      = '<<contenu>>';


    CNT_FLOTTE3_IN_METAL        = '<<metal>>';
    CNT_FLOTTE3_IN_CRISTAL      = '<<cristal>>';
    CNT_FLOTTE3_IN_DEUTERIUM    = '<<deuterium>>';
    CNT_FLOTTE3_IN_ORDRE        = '<<ordre>>';

    CNT_FLOTTE3_VAL_ORDRE_ATTAQUER   = '1';
    CNT_FLOTTE3_VAL_ORDRE_TRANSPORT  = '3';
    CNT_FLOTTE3_VAL_ORDRE_BASER      = '4';
    CNT_FLOTTE3_VAL_ORDRE_ESPIONNAGE = '6';
    CNT_FLOTTE3_VAL_ORDRE_COLONISER  = '7';
    CNT_FLOTTE3_VAL_ORDRE_EXPLOITER_RUINES  = '8';

    
    CNT_MESSAGE_IN_TYPEEFFACEMENT = '<<typeeffacement>>';
    CNT_MESSAGE_VAL_TYPEEFFACEMENT_SELECTED    = 'deletemarked';
    CNT_MESSAGE_VAL_TYPEEFFACEMENT_NONSELECTED = 'deletenonmarked';
    CNT_MESSAGE_VAL_TYPEEFFACEMENT_MSGMONTRES  = 'deleteallshown';
    CNT_MESSAGE_VAL_TYPEEFFACEMENT_TOUS        = 'deleteall';


    // Cette fonction ne peut pas figurer dans modCore, car elle utilise
    // modRecu, et modRecu utilise modCore
    // De plus, cette fonction doit être accessible partout, dans au lieu de
    // créer une nouvelle unité, on l'a place ici
    //procedure CalculQuandOnPourraConstruire(Element: TList; Prod: TList; CurrentProdParHeure, CurrRes: TOGRessourceAll);

    // Pour la page galaxie
    procedure GetReal(var str: string);

    {$IFDEF DEBUGCFILE}
       // Place la variable Page dans un fichier texte
       procedure DebugWebPage(Page: string);
    {$ENDIF}

    function mpcPageWebIsSessionExpireDBProblem(var PageWeb: string): boolean;

    //function mpcPageWebIsSessionExpireSessionProblem(var PageWeb: string): boolean;

implementation

function mpcPageWebIsSessionExpireSessionProblem(var PageWeb: string): boolean;
begin
    Result := false;


             // cette erreur se produit quand on change l'ip ou autre et qu'on nous signale
             // que la sessions n'est plus valide:
(*  <html><head><title>Ogame</title>
<link rel="stylesheet" type="text/css" href="formate.css">
<meta http-equiv="content-type" content="text/html; charset=ISO-8859-1">
</head><body text=#00FFFF backcolor=#00ff00><center><b><font color="#FF0000" size="+1">
Erreur</font></b><br>Votre session n\'est pas valable. Ceci peut avoir différentes raisons :<br><ol><li>
Vous vous êtes loggé plusieurs fois dans le même compte</li><li>Vous n'êtes plus en ligne avec la même adresse
IP que lors de votre dernier login (par ex. si la connexion a été interrompue)</li></ol><br>Veuillez vous relogger :
<a href="http://ogame.fr/" target=_top>Login</a><br><br></center></body></html>Vous jouez avec une autre IP que lors
de votre dernier login.<br> Ceci peut être provoqué par l'utilisation du navigateur AOL.<br>Prière de désactiver
la vérification IP dans les options ou d'utiliser un autre navigateur.

25/09/2006 02:40:38 - xcOnTimer - Téléchargement du menu à gauche
25/09/2006 02:40:38 - DownloadMenuLeft - Début
25/09/2006 02:40:38 - DownloadMenuLeft - Télécharge le menu à gauche: http://serveur.de/game/leftmenu.php?session=xxxxxxxxxxxx
25/09/2006 02:40:38 - DownloadMenuLeft - FParserMenu Echec
25/09/2006 02:40:38 - <html><head><title>Ogame</title>
<link rel="stylesheet" type="text/css" href="formate.css">
<meta http-equiv="content-type" content="text/html; charset=ISO-8859-1"></head><body text=#00FFFF backcolor=#00ff00><center><b><font color="#FF0000" size="+1">Erreur</font></b><br>Votre session n\'est pas valable. Ceci peut avoir différentes raisons :<br><ol><li>Vous vous êtes loggé plusieurs fois dans le même compte</li><li>Vous n'êtes plus en ligne avec la même adresse IP que lors de votre dernier login (par ex. si la connexion a été interrompue)</li></ol><br>Veuillez vous relogger : <a href="http://ogame.fr/" target=_top>Login</a><br><br></center></body></html>Vous jouez avec une autre IP que lors de votre dernier login.<br> Ceci peut être provoqué par l'utilisation du navigateur AOL.<br>Prière de désactiver la vérification IP dans les options ou d'utiliser un autre navigateur.
25/09/2006 02:40:38 - DownloadMenuLeft - FParserMenu Echec
25/09/2006 02:40:38 - xcOnTimer - Téléchargement du menu à gauche - Erreur FATALE -> Echec de parsing
25/09/2006 02:40:39 - xcOnTimer - Le login n'a jamais ete effectue"

             *)


    if pos(LangParsing.GetData('SessionErr_pos', 'euillez vous relogger'), PageWeb) < 1 then begin
       // inexistant
       exit;
    end;

    if pos(LangParsing.GetData('SessionErr2_pos', 'si la connexion a'), PageWeb) < 1 then begin
       // inexistant
       exit;
    end;

    if pos(LangParsing.GetData('SessionErr3_pos', 'du navigateur AOL'), PageWeb) < 1 then begin
       // inexistant
       exit;
    end;

    Result := true;
end;

function mpcPageWebIsSessionExpireDBProblem(var PageWeb: string): boolean;
var iMaxSize: integer;
begin
    // <script>setTimeout(window.parent.location='http://ogame.fr',1500);</script>Problème de DB 1 0 (Prière de vous relogger)<br>

    Result := false;

    (*
    try
       iMaxSize := StrToInt(LangParsing.GetData('DBProblemPageSizeMax', '1024'));
    except
       iMaxSize := 1024;
    end;


    if length(PageWeb) > iMaxSize then begin
       // page trop grande
       exit;
    end;
    *)


    if pos(LangParsing.GetData('DBProblemCond1_pos', 'Problème de DB'), PageWeb) < 1 then begin
       // inexistant
       Result := mpcPageWebIsSessionExpireSessionProblem(PageWeb);
       exit;
    end;

    if pos(LangParsing.GetData('DBProblemCond2_pos', 'de vous relogger'), PageWeb) < 1 then begin
       // inexistant
       Result := mpcPageWebIsSessionExpireSessionProblem(PageWeb);
       exit;
    end;

    Result := true;
end;




//////////////////////////
// Ecriture de message
//////////////////////////




procedure TParsingEcrireMessage.ScanOnStartTag(Sender: TObject; TagName: string; Attributes: TAttrList);
var CurrBalise: string;
    lng , xPos: integer;
begin

    if SameText(TagName, 'form') then begin
       // debut de la form
       // <form action="writemessages.php?session=0000000&gesendet=1&messageziel=8888888" method="post">
       CurrBalise := Attributes.Value('action');

       if pos('write', lowercase(CurrBalise)) > 0 then begin
          // ok, bonne form
          FInForm := true;

          FPostURL := CurrBalise;
       end;

       exit;
    end;

    if NoT(FInForm) then begin
       // on n'est pas dans la form
       exit;
    end;

    if SameText(TagName, 'input') then begin
       // <input type="text" name="to" size="40" value="XxxXxX [1:1:12]" />
       CurrBalise := Attributes.Value('type');

       if SameText(CurrBalise, 'text') then begin
          CurrBalise := Attributes.Value('name');

          if SameText(CurrBalise, 'to') then begin
             // destinataire, on ne le change pas
             FDestinataireChamp := Attributes.Value('value');


             if FPostData = '' then begin
                FPostData := CurrBalise + '=' + HTTPEncodePHPForParams(FDestinataireChamp);
             end else begin
                FPostData := FPostData + '&' + CurrBalise + '=' + HTTPEncodePHPForParams(FDestinataireChamp);
             end;


          end else if SameText(CurrBalise, 'betreff') then begin
             // sujet
             if FPostData = '' then begin
                FPostData := CurrBalise + '=' + CNT_ECRIRE_MSG_SUJET;
             end else begin
                FPostData := FPostData + '&' + CurrBalise + '=' + CNT_ECRIRE_MSG_SUJET;
             end;


          end else begin
             FError := true;
          end;

       end else if SameText(CurrBalise, 'submit') then begin
          // <input type="submit" value="Envoyer" />
          if FPostData = '' then begin
             FError := true;
          end else begin

          end;


       end else begin
          // champ de formulaire "input" inconnu
          FError := true;

       end;


    end else if SameText(TagName, 'textarea') then begin
       CurrBalise := Attributes.Value('name');

       // <textarea name="text" cols="40" rows="10" size="100" onkeyup="javascript:cntchar(500)">

       if SameText(CurrBalise, 'text') then begin
          // contenu du message
          if FPostData = '' then begin
             FError := true;
          end else begin
             FPostData := FPostData + '&' + CurrBalise + '=' + CNT_ECRIRE_MSG_CONTENU;
          end;


       end else begin
          FError := true;
       end;

    end;

end;

procedure TParsingEcrireMessage.ScanOnEndTag(Sender: TObject; TagName: string);
begin
    TagName := lowercase(TagName);

    if SameText(TagName, 'form') then begin
       // fin de la form
       FInForm := false;
    end;
end;

procedure TParsingEcrireMessage.ScanOnContent(Sender: TObject; Content: string);
begin
    // Rien à faire ici
end;

function TParsingEcrireMessage.ParseBuffer(const Tampon: string): boolean;
var xTampon: string;
begin

    inherited ParseBuffer(Tampon);


    FInForm   := false;
    FPostURL  := '';
    FPostData := '';


    FScanner.Execute;

    Result := NoT(FError);

end;

constructor TParsingEcrireMessage.Create(Scanner: TEasyXmlScanner);
begin
   inherited Create(Scanner);

end;

destructor TParsingEcrireMessage.Destroy;
begin


   inherited Destroy;
end;




{$IFDEF FORUM_PARSING}

function TParsingForumMemberList.GetToutEstOk: boolean;
begin
    Result := false;
    if (FNbAddItem = 30) or (FNbAddItem = 50) then begin
       // ok

    end else begin
       // echec
       exit;
    end;

    Result := FHtmlFinRencontre;
end;

function TParsingForumMemberList.IsValidItem: boolean;
begin
    if (CurrItem.uid > 0) and (CurrItem.pseudo <> '') and (CurrItem.regdate > 100) and (CurrItem.nbposts > -1) then begin
       Result := true;
    end else begin
       Result := false;
    end;
end;

procedure TParsingForumMemberList.InitItem;
begin
     CurrItem.uid := 0;
     CurrItem.pseudo := '';
     CurrItem.regdate := 0;
     CurrItem.nbposts := -1;

     // sur .org on ne connait pas la reg date...
     CurrItem.regdate := 500;
end;


procedure TParsingForumMemberList.ScanOnStartTag(Sender: TObject; TagName: string; Attributes: TAttrList);
var CurrBalise: string;
    lng , xPos: integer;
begin

    if NoT(FInDataUtile) then exit;

    TagName := lowercase(TagName);

    if TagName = 'tr' then begin
       Inc(FCurrTableLigne);
       FCurrTableColonne := 0;

       if IsValidItem then begin
          FListItems.Add(CurrItem);
          Inc(FNbAddItem);
       end;
       InitItem;


    end else if (TagName = 'td') or (TagName = 'th') then begin
       Inc(FCurrTableColonne);

    end else if TagName = 'a' then begin


       if (FCurrTableLigne > 0) and (FCurrTableColonne = 1) then begin
          CurrBalise := Attributes.Value('href');

          // profile.php?userid=0000001
          // profile.php?userid=88888&amp;sid=84454548888
          xPos := pos('profile.php', CurrBalise);

          if xPos > 0 then begin
             System.Delete(CurrBalise, 1, 11);

             xPos := pos('userid=', CurrBalise);
             if xPos = 0 then exit;

             System.Delete(CurrBalise, 1, xPos + length('userid=') - 1);



             xPos := pos('&', CurrBalise);
             if xPos > 0 then begin
                System.Delete(CurrBalise, xPos, maxint);
             end;

             try
                 CurrItem.uid := StrToIntDef(CurrBalise, -1);
             except
                 CurrItem.uid := -1;
                 FError := true;
             end;

          end;

       end;

    end;

end;

procedure TParsingForumMemberList.ScanOnEndTag(Sender: TObject; TagName: string); 
begin
    TagName := lowercase(TagName);

    if TagName = 'html' then begin
       FHtmlFinRencontre := true;
    end;
end;

procedure TParsingForumMemberList.ScanOnContent(Sender: TObject; Content: string);
var dd, mm, yyyy, xPos: integer;
begin
    if NoT(FInDataUtile) then begin

       if SameText(Content, 'Username') then begin
          FInDataUtile := true;

          FCurrTableLigne  := 0;
          FCurrTableColonne:= 0;

       end;
       exit;
    end;

    if FCurrTableLigne < 1 then exit;

(*
    case FCurrTableColonne of
          1: begin
                // le pseudo
                CurrItem.pseudo := Content;
             end;
          2: begin
                // PM bouton
             end;
          3: begin
                // Search bouton
             end;

          7: begin
                  // reg date
                  // 20.07.2005
                  dd   := sfcTokenGetInt(Content, 1, '.', -1);
                  mm   := sfcTokenGetInt(Content, 2, '.', -1);
                  yyyy := sfcTokenGetInt(Content, 3, '.', -1);

                  if (dd <= 0) or (mm <= 0) or (yyyy <= 0) then begin
                     FError := true;
                     CurrItem.regdate := 0;
                  end else begin
                     CurrItem.regdate := DateTimeToUnix(OptEncodeDateW(yyyy, mm, dd));
                  end;

             end;
          8: begin
                // nombre de posts
                Content := sfcRemplace(Content, ',', '');

                try
                   CurrItem.nbposts := StrToInt(Content);
                except
                   CurrItem.nbposts := -1;
                   FError := true;
                end;

             end;
    end;
            *)


    // .org
    case FCurrTableColonne of
          1: begin
                // le pseudo
                CurrItem.pseudo := Content;
             end;
          2: begin
                // email
             end;
          3: begin
                // homepage
             end;

             (*
             La reg date n'est pas présente dans la liste des membres sur les serveurs .org
          7: begin
                  // reg date
                  // 20.07.2005
                  dd   := sfcTokenGetInt(Content, 1, '.', -1);
                  mm   := sfcTokenGetInt(Content, 2, '.', -1);
                  yyyy := sfcTokenGetInt(Content, 3, '.', -1);

                  if (dd <= 0) or (mm <= 0) or (yyyy <= 0) then begin
                     FError := true;
                     CurrItem.regdate := 0;
                  end else begin
                     CurrItem.regdate := DateTimeToUnix(OptEncodeDateW(yyyy, mm, dd));
                  end;

             end;
             *)

          7: begin
                // nombre de posts
                Content := sfcRemplace(Content, ',', '');

                try
                   CurrItem.nbposts := StrToInt(Content);
                except
                   CurrItem.nbposts := -1;
                   FError := true;
                end;

             end;
    end;

end;



function TParsingForumMemberList.ParseBuffer(const Tampon: string): boolean;
var xTampon: string;
begin

    inherited ParseBuffer(Tampon);

    xTampon := sfcRemplace(Tampon, ' />', '>');

    InitItem;
    FNbAddItem := 0;
    FHtmlFinRencontre := false;

    FCurrTableLigne := 0;
    FCurrTableColonne := 0;
    FInDataUtile := false;


    FListItems.Clear;

    FScanner.LoadFromBuffer(PChar(xTampon));
    FScanner.Execute;

    Result := NoT(FError);

end;

constructor TParsingForumMemberList.Create(Scanner: TEasyXmlScanner);
begin
   inherited Create(Scanner);

   FListItems := TCollectionMemberItemFromList.Create;

end;

destructor TParsingForumMemberList.Destroy;
begin

   FListItems.Free;
   
   inherited Destroy;
end;




//////////////////////////////////////////////////////////////////////
// Profils                                                          //
//////////////////////////////////////////////////////////////////////




procedure TParsingForumProfil.ScanOnStartTag(Sender: TObject; TagName: string; Attributes: TAttrList);
var CurrBalise: string;
    lng , xPos: integer;
begin

    TagName := lowercase(TagName);

    if TagName = 'table' then begin
       FCurrTableLigne  := 0;
       FCurrTableColonne:= 0;

    end else if TagName = 'tr' then begin
       Inc(FCurrTableLigne);
       FCurrTableColonne := 0;

    end else if (TagName = 'td') or (TagName = 'th') then begin
       Inc(FCurrTableColonne);

    end else if TagName = 'a' then begin
       CurrBalise := Attributes.Value('href');

       xPos := pos('search.php?action=user&userid=', CurrBalise);
       if xPos > 0 then begin
          System.Delete(CurrBalise, 1, length('search.php?action=user&userid='));

          CurrBalise := trim(CurrBalise);

          xPos := pos('&', CurrBalise);
          if xPos > 0 then
             System.Delete(CurrBalise, xPos, maxint);

          FUID := StrToIntDef(CurrBalise, -2);
       end;

    end;

    
    // search.php?action=user&amp;userid=121212
    // <a href="search.php?action=user&amp;userid=121212">

end;

procedure TParsingForumProfil.ScanOnEndTag(Sender: TObject; TagName: string);
begin

end;

function DecryptForumEmail(s: string): string;
var nb: string;
    inb, i: integer;
begin

    Result := '';
    if length(s) <= 0 then exit;


    for i := 1 to length(s) do begin
        if s[i] in sfc_ChiffresSet then begin
           nb := nb + s[i];

        end else begin

           if nb <> '' then begin
               try
                  inb := StrToInt(nb);
               except
                  inb := -1;
               end;

               if (inb > 0) and  (inb < 256) then begin
                  Result := Result + Chr(inb);
               end;

               nb := '';
           end;
        end;

    end;


end;


procedure TParsingForumProfil.ScanOnContent(Sender: TObject; Content: string);
label lRedo;
var dd, mm, yyyy, xPos: integer;
    dtx: TDateTime;
begin


    // Profile for

    if SameText(Content, 'No declaration') then begin
       Content := '';
    end;


lRedo:
    if FCurrTableColonne = 1 then
       FNext := pnwNeant;

    if (pos('&raquo; Profile for', Content) > 0) or (pos('| Profile for', Content) > 0) then begin
       xPos := pos('&raquo; Profile for', Content);

       if xPos = 0 then begin
          xPos := pos('| Profile for', Content);
          System.Delete(Content, 1, xPos + length('| Profile for') - 1);

       end else begin
          System.Delete(Content, 1, xPos + length('&raquo; Profile for') - 1);
       end;


       FPseudo := trim(Content);
       exit;
    end;

    case FNext of
         pnwNeant: begin
                if pos('Registration Date', Content) = 1 then
                   FNext := pnwRegDate;

                if pos('Rank', Content) = 1 then begin
                   FNext := pnwRank;
                   exit;
                end;

                if pos('Posts', Content) = 1 then
                   FNext := pnwPosts;

                if pos('Last Active', Content) = 1 then
                   FNext := pwnLastActive1;

                if pos('Last Post', Content) = 1 then
                   FNext := pwnLastPost;

                if pos('ICQ N', Content) = 1 then
                   FNext := pnwICQ;

                if pos('AOL Messenger', Content) = 1 then
                   FNext := pnwAOL;

                if pos('Yahoo!', Content) = 1 then
                   FNext := pnwYahoo;

                if pos('MSN Messenger', Content) = 1 then begin
                   FNext := pnwMSN;
                   exit;
                end;

                if pos('Email', Content) = 1 then
                   FNext := pnwEmail;

                if pos('Homepage', Content) = 1 then
                   FNext := pnwHomePage;



                if pos('Gender', Content) = 1 then
                   FNext := pnwGender;

                if pos('Birthday', Content) = 1 then
                   FNext := pnwDateNaissance;

                if (pos('Univers', Content) = 1) or (pos('Universum', Content) = 1) or (pos('Servidor', Content) = 1) then
                   FNext := pnwUnivers;

                if (pos('Location', Content) = 1) or (pos('Ubicación', Content) = 1)  then
                   FNext := pnwLocation;

                if (pos('Interests', Content) = 1) or (pos('Intereses', Content) = 1) then
                   FNext := pnwInterest;

                if (pos('Occupation', Content) = 1) or (pos('Ocupación', Content) = 1)  then
                   FNext := pnwOccupation;


            end;

         pnwRegDate: begin

                  //dd   := sfcTokenGetInt(Content, 1, '.', -1);
                  //mm   := sfcTokenGetInt(Content, 2, '.', -1);
                  //yyyy := sfcTokenGetInt(Content, 3, '.', -1);

                  // .org board:
                  // 09-13-2006
                  // mm dd yyyy
                  dd   := sfcTokenGetInt(Content, 2, '-', -1);
                  mm   := sfcTokenGetInt(Content, 1, '-', -1);
                  yyyy := sfcTokenGetInt(Content, 3, '-', -1);

                  if (dd <= 0) or (mm <= 0) or (yyyy <= 0) then begin
                     FError := true;
                     FRegDate := 0;
                  end else begin
                     FRegDate := DateTimeToUnix(OptEncodeDateW(yyyy, mm, dd));
                  end;

                  FNext := pnwNeant;
                  
            end;

         pnwRank: begin
                // le rank peut être vide
                // dans ce cas là, le OnContent n'est pas exécuté...
                // le rank est suivit d'une image
                FRank := Content;
                FNext := pnwNeant;

            end;

         pnwPosts: begin
                // 5,020 (8.53 per day)
                Content := sfcTokenGet(Content, 1, ' ');
                Content := sfcRemplace(Content, ',', '');

                try
                   FPosts := StrToInt(Content);
                except
                   FPosts := -1;
                   FError := true;
                end;

                FNext := pnwNeant;
            end;

         pwnLastActive1: begin
               if SameText(Content, 'Today') or SameText(Content, 'Today,') or (pos('today', lowercase(Content)) > 0) then begin
                  FLastActive := DateTimeToUnix(Now);
               end else if SameText(Content, 'Yesterday') or SameText(Content, 'Yesterday,') or (pos('esterday', Content) > 0) then begin
                  FLastActive := DateTimeToUnix(Now) - 86400;

               end else begin
                  // 01.06.2006
                  if length(Content) > 5 then begin
                     dd   := sfcTokenGetInt(Content, 1, '.', -1);
                     mm   := sfcTokenGetInt(Content, 2, '.', -1);
                     yyyy := sfcTokenGetInt(Content, 3, '.', -1);


                     if (dd <= 0) or (mm <= 0) or (yyyy <= 0) then begin
                        dd   := sfcTokenGetInt(Content, 2, '-', -1);
                        mm   := sfcTokenGetInt(Content, 1, '-', -1);
                        yyyy := sfcTokenGetInt(Content, 3, '-', -1);
                     end;

                     if (dd <= 0) or (mm <= 0) or (yyyy <= 0) then begin
                        FError := true;
                        FLastActive := 0;
                     end else begin
                        FLastActive := DateTimeToUnix(OptEncodeDateW(yyyy, mm, dd));
                     end;

                  end else begin
                     FLastActive := 0;
                  end;

               end;

               FNext := pwnLastActive2;
            end;

         pwnLastActive2: begin
                // l'heure
                // on ignore
                FNext := pnwNeant;
            end;

         pwnLastPost: begin
                // dernier post

                if SameText(Content, 'Posted on:') then begin
                   FNext := pwnLastPostWhen;

                end else begin

                   if pos('posted on', lowercase(Content)) > 0 then begin
                      // Posted on: 30.05.2006
                      // Posted on: Yesterday,
                      System.Delete(Content, 1, length('Posted on:'));
                      Content := trim(Content);

                      Content := sfcRemplace(Content, ',', '');
                      if SameText(Content, 'Yesterday') then begin
                           FLastPostDate := DateTimeToUnix(Now) - 86400;

                      end else begin
                           dd   := sfcTokenGetInt(Content, 1, '.', -1);
                           mm   := sfcTokenGetInt(Content, 2, '.', -1);
                           yyyy := sfcTokenGetInt(Content, 3, '.', -1);


                           dd   := sfcTokenGetInt(Content, 2, '-', -1);
                           mm   := sfcTokenGetInt(Content, 1, '-', -1);
                           yyyy := sfcTokenGetInt(Content, 3, '-', -1);


                           if (dd <= 0) or (mm <= 0) or (yyyy <= 0) then begin
                              FError := true;
                              FLastPostDate := 0;
                           end else begin
                              FLastPostDate := DateTimeToUnix(OptEncodeDateW(yyyy, mm, dd));
                           end;
                      end;


                      FNext := pnwNeant;
                   end;

                end;
            end;

            
         pwnLastPostWhen: begin
                // Today seulement...
                if SameText(Content, 'Today') then begin
                    FLastPostDate := DateTimeToUnix(Now);
                end;

                FNext := pnwNeant;
            end;


         pnwICQ : begin
               FICQ  := Content;
               FNext := pnwNeant;
            end;

         pnwAOL: begin
               FAOL  := Content;
               FNext := pnwNeant;
            end;

         pnwYahoo: begin
               FYahoo := Content;
               FNext  := pnwNeant;
            end;

         pnwMSN: begin
               FMsn   := Content;
               FNext  := pnwNeant;
            end;

         pnwEmail: begin
               FEmail := DecryptForumEmail(Content);
               FNext  := pnwNeant;
            end;

         pnwHomePage: begin
               FHomepage := Content;
               FNext     := pnwNeant;
            end;

         pnwGender: begin
                if SameText(Content, 'Female') then begin
                   FGender := 2;
                end else if SameText(Content, 'Male') then begin
                   FGender := 1;
                end else begin
                   FGender := 0;
                end;

                FNext     := pnwNeant;
            end;

         pnwDateNaissance: begin
                // 17.12.1990
                if Content <> '' then begin
                   // transforme en yyyy.mm.dd
                   FDateNaissance := sfcTokenGet(Content, 3, '.') + sfcTokenGet(Content, 2, '.') + sfcTokenGet(Content, 1, '.');
                end;

                FNext     := pnwNeant;
            end;

         pnwUnivers: begin
                FUnivers := sfcRemplace(Content, 'Univers', 'Uni');
                FNext     := pnwNeant;
            end;

         pnwLocation: begin
               FLocation := Content;
               FNext     := pnwNeant;
            end;

         pnwInterest: begin
               FInterests := Content;
               FNext      := pnwNeant;
            end;

         pnwOccupation: begin
               FOccupation := Content;
               FNext       := pnwNeant;
            end;

    end;


end;

function TParsingForumProfil.GetSQLReq: string;
var xPseudo, xRank, xICQ, xAOL, xYahoo: string;
    xMsn, xEmail, xHomePage, xDTN, xUnivers, xLocation, xInterests, xOccupation: string;
begin
    Result := '';

    if IsValidProfil = false then
       exit;


    xPseudo := sfcAddSlashes(FPseudo);
    xRank   := sfcAddSlashes(FRank);
    xICQ    := sfcAddSlashes(FICQ);
    xAOL    := sfcAddSlashes(FAOL);
    xYahoo  := sfcAddSlashes(FYahoo);

    xMsn       := sfcAddSlashes(FMsn);
    xEmail     := sfcAddSlashes(FEmail);
    xHomePage  := sfcAddSlashes(FHomepage);
    xDTN       := sfcAddSlashes(FDateNaissance);
    xUnivers   := sfcAddSlashes(FUnivers);
    xLocation  := sfcAddSlashes(FLocation);
    xInterests := sfcAddSlashes(FInterests);
    xOccupation := sfcAddSlashes(FOccupation);


    Result := 'REPLACE INTO `' + FNomDeLaTable + '` (uid, status, pseudo, regdate, rank, posts, lastpostdate, icq, ' +
              'aol, yahoo, msn, email, homepage, gender, ' +
              'dtnaissance, univers, location, interests, occupation)' +
              ' VALUES (' +
              format('%d, 1, ''%s'', %d, ''%s'', %d, %d, ''%s'', ', [FUID, xPseudo, FRegDate, xRank, FPosts, FLastPostDate, xICQ]) +
              format('''%s'', ''%s'', ''%s'', ''%s'', ''%s'', %d, ', [xAOL, xYahoo, xMsn, xEmail, xHomePage, FGender]) +
              format('''%s'', ''%s'', ''%s'', ''%s'', ''%s'');',  [xDTN, xUnivers, xLocation, xInterests, xOccupation]);



end;

function TParsingForumProfil.IsValidProfil: boolean;
begin
    Result := false;


    if (FUID > 0) and (FPseudo <> '') and (FRegDate > 0) then begin
       Result := true;

    end;
    
end;

procedure TParsingForumProfil.Init;
begin
       FUID    := -1;
       FPseudo := '';

       FRegDate   := 0;
       FRank      := '';
       FPosts     := 0;
       FLastPostDate:= 0;
       FLastActive  := 0;
       FICQ    := '';
       FAOL    := '';
       FYahoo  := '';
       FMsn    := '';
       FEmail  := '';
       FHomepage   := '';
       FGender        := 0;
       FDateNaissance := '';
       FUnivers    := '';
       FLocation   := '';
       FInterests  := '';
       FOccupation := '';


end;

function TParsingForumProfil.ParseBuffer(const Tampon: string): boolean;
var xTampon: string;
    xPos: integer;
begin
    // Première implémentation de la fonction depuis la classe mère
    // Pas d'héritage donc

    inherited ParseBuffer(Tampon);

    xTampon := sfcRemplace(Tampon, ' />', '>');
    xTampon := sfcRemplace(Tampon, '&eacute;', 'é');
    xTampon := sfcRemplace(Tampon, '&egrave;', 'è');
    xTampon := sfcRemplace(Tampon, '&agrave;', 'à');

      Init;

    FPosition := 0;
    FNext := pnwNeant;

    FScanner.LoadFromBuffer(PChar(xTampon));
    FScanner.Execute;

    Result := NoT(FError);


end;

constructor TParsingForumProfil.Create(Scanner: TEasyXmlScanner);
begin
    inherited Create(Scanner);

    FNomDeLaTable := 'og_officiel';
end;

destructor TParsingForumProfil.Destroy;
begin
    inherited Destroy;
end;

{$ENDIF}


////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
// Liste des messages pour récupérer les rapports d'espionnage

(*
<tr>
       <td class="b"> </td><td colspan="3" class="b"><table width=400><tr><td class=c colspan=4>Matières premières sur PlanetName [9:8:9] pour 1-1 21:50:32</td></tr>
<tr><td>Métal:</td><td>83135</td>
<td>Cristal:</td><td>30538</td></tr>

<tr><td>Deutérium:</td><td>12859</td>
<td>Énergie:</td><td>4536</td></tr>
</table>
<table width=400><tr><td class=c colspan=4>Flottes     </td></tr>
</table>
<center> Probabilité de défense contre-espionnage:0%</center>
</td>
    </tr>

doit être converti en:

Matières premières sur PlanetName [1:1:9] pour 10-14 21:50:32
Métal:	83135 	Cristal:	30538
Deutérium:	12859 	Énergie:	4536
Flottes
Probabilité de défense contre-espionnage:0%
*)


procedure TParsingMessagesList.SetURLOfThisPage(Valeur: string);
var i: integer;
begin
    FPageToPost  := sHTML_Get_URL_Lien(Valeur, FPageToPost);

    FMessageList.SetURLOfPage(Valeur);


    inherited SetURLOfThisPage(Valeur);
end;


constructor TParsingMessagesList.Create(Scanner: TEasyXmlScanner);
begin
    inherited Create(Scanner);

    FMessageList := TCollectionOGMessage.Create;
end;

destructor TParsingMessagesList.Destroy;
begin

    FMessageList.Free;

    inherited Destroy;
end;

procedure TParsingMessagesList.InitMsg;
begin
    FCurrMsg.CheckBox := '';
    FCurrMsg.Date     := '';
    FCurrMsg.Emetteur := '';
    FCurrMsg.Sujet    := '';
    FCurrMsg.Contenu  := '';
    FCurrMsg.RapportCombatLink := '';

    FCurrMsg.DateInt.Mois    := 0;
    FCurrMsg.DateInt.Jour    := 0;
    FCurrMsg.DateInt.Heure   := 0;
    FCurrMsg.DateInt.Minute  := 0;
    FCurrMsg.DateInt.Seconde := 0;
end;

function TParsingMessagesList.IsValidMsg: boolean;
label lUsageCurrYear;
var xMonth: word;
    MsgDate: TDateTime;
begin

    Result := true;

    if (FCurrMsg.CheckBox = '') or (FCurrMsg.Date = '') or (FCurrMsg.Emetteur = '') or (FCurrMsg.Contenu = '') then
       Result := false;

    if Result = false then begin
       if FCurrMsg.RapportCombatLink <> '' then begin
          // le contenu est vide pour un rapport de combat
          if (FCurrMsg.CheckBox = '') or (FCurrMsg.Date = '') or (FCurrMsg.Emetteur = '') then begin
             Result := false;
          end else begin
             Result := true;
          end;
       end;
    end;

    if Result then begin
       Result := mmlIsValidDate(FCurrMsg.DateInt);

       if Result then begin
          // ok, message valide
          // on estime la date
          MsgDate := EncodeTime(FCurrMsg.DateInt.Heure, FCurrMsg.DateInt.Minute, FCurrMsg.DateInt.Seconde, 0);


          xMonth := ThisMonth;


          if xMonth = FCurrMsg.DateInt.Mois then begin
             // même mois
             // on utilise l'année actuelle
lUsageCurrYear:
             MsgDate := MsgDate + EncodeDate(ThisYear, FCurrMsg.DateInt.Mois, FCurrMsg.DateInt.Jour);
             FCurrMsg.DateEstimation := DateTimeToUnix(MsgDate);

          end else  begin
             // le mois est plus petit que le mois actuel
             // ce n'est pas forcément un changement d'année
             // SAUF, si les mois concernés sont décembre et janvier
             // on part du principe que les messages peuvent dater que plusieurs jours
             // (15 au maximum on va dire)
             // La fonction de date a de toute façon pour but un usage immédiat lors de
             // l'extraction d'un rapport d'espionnage pour le sondage avant impact
             // ou le sondage avant d'attaquer (pour la liste d'attente de raid)

             if (xMonth > 1) and (xMonth < 12) then begin
                // ok, on utilise l'année actuelle
                goto lUsageCurrYear;

             end else begin
                // le mois actuel est soit janvier, soit décembre

                if (xMonth = 12) and (FCurrMsg.DateInt.Mois > 6) then begin
                   // cas où FCurrMsg.DateInt.Mois = 11
                   // l'heure du pc avance par rapport au jeu, et on est à la fin du mois de novembre
                   // on utilise l'année actuelle
                   goto lUsageCurrYear;

                end else if (xMonth = 1) and (FCurrMsg.DateInt.Mois < 6) then begin
                   // cas où FCurrMsg.DateInt.Mois = 2
                   // l'heure du pc retarde par rapport au jeu, et on est à la fin du mois de janvier
                   // on utilise l'année actuelle
                   goto lUsageCurrYear;

                   
                end else begin
                   // sinon, il y a un changement d'année possible...
                   
                   if (xMonth = 12) then begin
                      // dans ce cas, FCurrMsg.DateInt.Mois <= 6 car le > 6 a déjà été traité
                      MsgDate := MsgDate + EncodeDate(ThisYear + 1, FCurrMsg.DateInt.Mois, FCurrMsg.DateInt.Jour);
                      FCurrMsg.DateEstimation := DateTimeToUnix(MsgDate);
                   end else begin
                      // xMonth = 1 et FCurrMsg.DateInt.Mois >= 6 car < 6 déjà traité
                      MsgDate := MsgDate + EncodeDate(ThisYear - 1, FCurrMsg.DateInt.Mois, FCurrMsg.DateInt.Jour);
                      FCurrMsg.DateEstimation := DateTimeToUnix(MsgDate);
                   end;
                end;

             end;
             
          end;



       end;
    end;
end;


procedure TParsingMessagesList.ScanOnStartTag(Sender: TObject; TagName: string; Attributes: TAttrList);
var CurrBalise: string;
    lng, xPos : integer;
begin

    TagName := lowercase(TagName);

    if TagName = 'table' then begin
        if FInTable < 0 then exit;

        Inc(FInTable);

    end else if TagName = 'form' then begin

       // <form action="messages.php?session=000000" method="POST">
       CurrBalise := Attributes.Value('action');

       FPageToPost := CurrBalise;

       // Indique que l'on est dans le tableau
       FInTable := 1;
       FCurrTableLigne := 0;
       FCurrTableColonne := 0;

       Inc(FNbFormTag);
       exit;
    end;

    if FInTable < 0 then exit;


    if TagName = 'tr' then begin
        if FInTable = 1 then begin
           Inc(FCurrTableLigne);
           FCurrTableColonne := 0;

        end else if FInTable > 1 then begin
           // On est alors dans un rapport d'espionnage
           // Rajoute un saut de ligne
           if FThisLigneIsContent = FCurrTableLigne then begin
              lng := length(FCurrBuffer);
              if lng > 0 then begin
                 // Vérifie si le retour à la ligne n'existe pas déjà
                 if FCurrBuffer[lng] <> #$0A then
                    FCurrBuffer := FCurrBuffer + #$0D#$0A;

              end;
           end;

        end;

        
    end else if (TagName = 'td') or (TagName = 'th') then begin
        if FInTable = 1 then begin
           Inc(FCurrTableColonne);
        end;

    end else if TagName = 'a' then begin
        // pour la sauvegarde de rapport de combat
(*<tr><th><input type="checkbox" name="delmes111111" /></th>
     <th>10-4 14:27:04</th>
     <th>Fleet Command </th>
     <th><a href="#" onclick="fenster('bericht.php?xtid&bericht=11111', 'Bericht');" ><span class="combatreport">Battle Report (0,7) [1:1:5] (V:0,A:0)</span></a></th>
</tr>*)

        if FCurrTableColonne <> 4 then begin
           // le lien est dans le sujet, c'est à dire dans la colonne 4
           exit;
        end;

        CurrBalise := Attributes.Value('onclick');

        // on n'obtient pas directement le lien, mais plutôt:
        // fenster('bericht.php?xtid&bericht=11111111', 'Bericht');
        if CurrBalise <> '' then begin
           xPos := pos('''', CurrBalise);

           if xPos > 0 then begin
              System.Delete(CurrBalise, 1, xPos);

              xPos := pos('''', CurrBalise);
              if xPos > 0 then begin
                 System.Delete(CurrBalise, xPos, maxint);

                 CurrBalise := trim(CurrBalise);
                 
                 if length(CurrBalise) > 12 then begin
                    // CurrBalise contient maintenant le lien à télécharger
                    FCurrMsg.RapportCombatLink := CurrBalise;
                    FIsInRapportCombat := true;
                 end;

              end;
           end;
        end;




    end else if TagName = 'input' then begin
        // <input type="checkbox" name="delmes111111111" />
        // <input type="hidden" name="messages" value="1" />
        // <input type="checkbox" name="fullreports"  />

        CurrBalise := lowercase(trim(Attributes.Value('type')));

        if CurrBalise = 'checkbox' then begin
            // comment traiter les checkbox ?
            // car si il y en a une qui n'est pas coché, elle ne figure pas
            // dans les données à poster


            // La ligne suivante sera un contenu, on peut également identifié
            // le contenu avec la balise <td colspan="3" class="b">
            // qui figure avant chaque contenu


            lng := length(FCurrBuffer);
            if lng > 0 then begin
               if FCurrBuffer[lng] = #$0A then begin
                  System.Delete(FCurrBuffer, lng - 1, 2);
               end;

            end;

            FCurrMsg.Contenu := FCurrBuffer;

            if IsValidMsg then begin
               // ajoute le message le précédent
               // puis on initialise le nouveau message
               FMessageList.Add(FCurrMsg);

            end;

            FThisLigneIsContent := FCurrTableLigne + 1;
            FCurrBuffer := '';
            InitMsg;

            FCurrMsg.CheckBox := trim(Attributes.Value('name'));

        end else if CurrBalise = 'hidden' then begin
            if FDataToPost = '' then
               FDataToPost :=  trim(Attributes.Value('name')) + '=' + trim(Attributes.Value('value'))
            else
               FDataToPost := FDataToPost + '&' + trim(Attributes.Value('name')) + '=' + trim(Attributes.Value('value'));

        end else if CurrBalise = 'submit' then begin
            // <input type="submit" value="ok" />
               
        end else begin
            // Non prévu
            // Erreur
            FError := true;
        end;


    end else if TagName = 'center' then begin

              lng := length(FCurrBuffer);
              if lng > 0 then begin
                 // Vérifie si le retour à la ligne n'existe pas déjà
                 if FCurrBuffer[lng] <> #$0A then
                    FCurrBuffer := FCurrBuffer + #$0D#$0A;

              end;

    end else if TagName = 'select' then begin


(*   <select name="deletemessages">
       <option value="deletemarked">Effacer les messages sélectionnés</option>
       <option value="deletenonmarked">Effacer tous les messages qui ne sont pas choisis</option>
       <option value="deleteallshown">Effacer tous les messages montrés </option>
       <option value="deleteall">Effacer tous les messages</option>
      </select>
      *)

        CurrBalise := lowercase(trim(Attributes.Value('name')));

        if SameText(CurrBalise, 'deletemessages') then begin
            if FDataToPost = '' then
               FDataToPost :=  trim(Attributes.Value('name')) + '=' + CNT_MESSAGE_IN_TYPEEFFACEMENT
            else
               FDataToPost := FDataToPost + '&' + trim(Attributes.Value('name')) + '=' + CNT_MESSAGE_IN_TYPEEFFACEMENT;

               
            if IsValidMsg then begin
               // ajoute le message

            end;
            FCurrBuffer := '';
            InitMsg;


        end else begin
           // Select inconnu
           FError := true;

        end;

    end else if TagName = 'option' then begin
        CurrBalise := lowercase(trim(Attributes.Value('value')));

        if SameText(CurrBalise, 'deletemarked') then begin

        end else if SameText(CurrBalise, 'deletenonmarked') then begin
        end else if SameText(CurrBalise, 'deleteallshown') then begin
        end else if SameText(CurrBalise, 'deleteall') then begin

        end else begin
           // Option inconnue
           FError := true;

        end;

    end;

end;

procedure TParsingMessagesList.ScanOnEndTag(Sender: TObject; TagName: string);
var CurrBalise: string;
    lng: integer;
begin

    if FInTable < 0 then exit;
    TagName := lowercase(TagName);

    if TagName = 'table' then begin
       Dec(FInTable);

    end else if TagName = 'tr' then begin

        if FInTable > 1 then begin
           // On est alors dans un rapport d'espionnage
           // Rajoute un saut de ligne (on le place normalement dans l'ouverture
           // de ligne, mais ils ne respectent pas les stardards (volontairement probablement)
           if FThisLigneIsContent = FCurrTableLigne then begin
              lng := length(FCurrBuffer);

              if lng > 0 then begin
                 if FCurrBuffer[lng] <> #$0A then
                    FCurrBuffer := FCurrBuffer + #$0D#$0A;

              end;
           end;

        end;

    end;
    
end;

procedure TParsingMessagesList.ScanOnContent(Sender: TObject; Content: string);
var lng: integer;
begin
    if FInTable < 0 then exit;
    if FCurrTableColonne < 1 then exit;
    if FCurrTableLigne < 2 then exit;


    if FIsInRapportCombat then begin
       // on est dans un rapport de combat
       FIsInRapportCombat := false;

       if FCurrTableColonne = 4 then begin
          // le lien est dans le sujet, c'est à dire dans la colonne 3
          // Battle Report (0,7) [2:1:5] (V:0,A:0)

          // Le rapport de combat n'ayant pas de contenu, on lui en défini un:
          //FCurrMsg.Contenu := Content;


       end;

    end;

    if FThisLigneIsContent = FCurrTableLigne then begin
       lng := length(FCurrBuffer);

       if lng > 0 then begin

          if FCurrBuffer[lng] = #$0A then
             FCurrBuffer := FCurrBuffer + Content
          else
             FCurrBuffer := FCurrBuffer + ' ' + Content;

       end else
          FCurrBuffer := Content;

    end else begin

        case FCurrTableColonne of
             2: begin
                    // Les dates semblent être au même format tout le temps
                    // mais il manque l'année...
                    //  fr: 10-19 15:29:22
                    // org: 10-20 01:21:24
                    FCurrMsg.Date    := Content;
                    FCurrMsg.DateInt := mmlParsingDate(Content);

                    // l'estimation s'effectue dans la vérification de validité du message
                    FCurrMsg.DateEstimation := 0;

                end;
             3: begin
                    FCurrMsg.Emetteur := Content;
                end;
             4: begin
                    // Le sujet est en deux partie dans la nouvelle version car
                    // les coordonnées sont sous forme de lien (balise A)
                    if FCurrMsg.Sujet = '' then begin
                       FCurrMsg.Sujet := Content;
                    end else begin
                       FCurrMsg.Sujet := FCurrMsg.Sujet + ' ' + Content;
                    end;

                end;

        end;

    end;
    


end;

function TParsingMessagesList.ParseBuffer(const Tampon: string): boolean;
begin
    inherited ParseBuffer(Tampon);

    FDataToPost := '';
    FPageToPost := '';

    FInTable := -1;

    FThisLigneIsContent := -1;

    InitMsg;
    FNbFormTag := 0;

    FMessageList.Clear;

    FError := false;



    FScanner.Execute;

    Result := NoT(FError);

end;













////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
// Flotte 4 - Confirmation d'envoi

procedure TParsingFlotte4_ConfirmationEnvoi.ScanOnStartTag(Sender: TObject; TagName: string; Attributes: TAttrList);
var CurrBalise: string;
begin

    TagName := lowercase(TagName);

    if TagName = 'table' then begin

        FInTable := true;
        FNextContent := pf4Neant;
        FCurrTableLigne   := 0;  // integer;
        FCurrTableColonne := 0;  // integer;

    end else if TagName = 'tr' then begin
        Inc(FCurrTableLigne);
        FCurrTableColonne := 0;

    end else if (TagName = 'td') or (TagName = 'th') then begin
        Inc(FCurrTableColonne);

    end;


end;

procedure TParsingFlotte4_ConfirmationEnvoi.ScanOnEndTag(Sender: TObject; TagName: string);
begin

    TagName := lowercase(TagName);

    if TagName = 'table' then begin
       FInTable := false;

    end else if SameText(TagName, 'html') then begin
       // permet de s'assurer que la page web a bien été téléchargé en cas d'erreur de parsing
       FBaliseFinHTMLTrouve := true;
    end;


end;

procedure TParsingFlotte4_ConfirmationEnvoi.ScanOnContent(Sender: TObject; Content: string);
var sContent: string;
begin


   sContent := trim(lowercase(Content));




   // Erreur commune à toutes les erreurs
   if pos(LangParsing.GetData('flotte4_erreur_lwpos_pas_envoye', 'a pas pû être envoyée'), sContent) > 0 then begin
      // La flotte n'a pas pû être envoyée !
      FGeneralError := true;
   end;

   // Multi-alarm! Player can't be approached with fleet!


   
   if SameText(Content, 'admin') then begin
      // La flotte n'a pas pû être envoyée !
      // Admin
      FPlaneteAdmin := true;

   end else if pos(LangParsing.GetData('flotte4_erreur_lwpos_planete_non_habite', 'planète inhabité'), sContent) > 0 then begin
      // 0.70: planète inhabité
      // Planète inhabité ou planète habité et en cour d'être colonisé!
      FPlaneteDestinationVide := true;

   end else if pos(LangParsing.GetData('flotte4_erreur_lwpos_deuterium_need', 'as assez de carburant'), sContent) > 0 then begin
      // Pas assez de carburant !
      FDeuteriumError := true;

      
   end else if pos(LangParsing.GetData('flotte4_erreur_lwpos_protect_des_noob', 'protection des joueurs faibles'), sContent) > 0 then begin
      // 0.70: protection des noobs
      // Vous ne pouvez pas espionner cette planète, la protection des joueurs faibles vous en empêche !
      // This planet can't be approached because of newbie protection!
      FPlaneteDestinationNoobProtect := true;


   end else if pos(LangParsing.GetData('flotte4_erreur_lwpos_en_vacance', 'joueur est en mode vacance'), sContent) > 0 then begin
      // 0.70: joueur est en mode vacance
      FPlaneteIsInModeVacance := true;


   end else if pos(LangParsing.GetData('flotte4_swiss_neutral', 'witzerland is neutral'), sContent) > 0 then begin
      // Uni béta: la suisse est neutre
      // Switzerland is neutral
      // avec le message:
      // No ships selected or not enough ships available!
      FPlaneteDestinationNoobProtect := true;


   end;


   // A cause de la protection des noobs tu ne peux pas espionner cette planète!


   if FInTable = false then exit;
   if FCurrTableLigne < 2 then exit;


   // FFlotteArriveeIsInvalide

   if FCurrTableColonne = 1 then begin










      // On est dans la page de confirmation d'envoi
      // Et on extrait les champs pour être certain d'avoir
      // reussi l'envoi de la flotte


      if SameText(Content, LangParsing.GetData('flotte4_so_Ordre', 'Ordre')) then begin
         FNextContent := pf4Neant;
      end else if SameText(Content, LangParsing.GetData('flotte4_st_Distance', 'Distance')) then begin
         FNextContent := pf4Distance;
      end else if SameText(Content, LangParsing.GetData('flotte4_st_Vitesse', 'Vitesse')) then begin
         FNextContent := pf4Vitesse;
      end else if SameText(Content, LangParsing.GetData('flotte4_st_Consommation', 'Consommation')) then begin
         FNextContent := pf4Consomation;
      end else if SameText(Content, LangParsing.GetData('flotte4_st_Depart', 'Départ')) then begin
         FNextContent := pf4Depart;
      end else if SameText(Content, LangParsing.GetData('flotte4_st_Objectif', 'Objectif')) then begin
         FNextContent := pf4Arrivee;

      end else if SameText(Content, LangParsing.GetData('flotte4_st_TempsArrivée', 'Temps d''arrivée')) then begin
         // ignore, les autres champs suffissent pour savoir si on a reussit l'envoi
         FNextContent := pf4Neant;
      end else if SameText(Content, LangParsing.GetData('flotte4_st_TempsRetour', 'Temps de retour')) then begin
         FNextContent := pf4Neant;
      end;




   end else if FCurrTableColonne = 2 then begin
       if FNextContent = pf4Neant then exit;

       Content := trim(Content);

       case FNextContent of
           pf4Distance   : FFlotteDistance    := StrToIntDef(Content, -1);
           pf4Vitesse    : FFlotteVitesse     := StrToIntDef(Content, -1);
           pf4Consomation: FFlotteConsomation := StrToIntDef(Content, -1);

           pf4Depart : FFlotteDepart  := mpcExtractPlanetLocation(Content);
           pf4Arrivee: FFlotteArrivee := mpcExtractPlanetLocation(Content);
       end;

       // Réinitialise le flag
       FNextContent := pf4Neant;
   end;

end;

function TParsingFlotte4_ConfirmationEnvoi.GetPlaneteCantBeAccessible: boolean;
begin
    Result := false;

    if FPlaneteDestinationVide or FPlaneteAdmin or FPlaneteDestinationNoobProtect or
       FPlaneteIsInModeVacance or FGeneralError then
       Result := true;

end;

function TParsingFlotte4_ConfirmationEnvoi.ParseBuffer(const Tampon: string): boolean;
begin
    Lock;

    inherited ParseBuffer(Tampon);

    with FFlotteDepart do begin
        Galaxie := -1;
        SystemSolaire := -1;
        Position := -1;
    end;
    with FFlotteArrivee do begin
        Galaxie := -1;
        SystemSolaire := -1;
        Position := -1;
    end;

    FFlotteConsomation := -1;
    FFlotteVitesse     := -1;
    FFlotteDistance    := -1;

    FPlaneteDestinationVide := false;
    FPlaneteDestinationNoobProtect := false;
    FPlaneteIsInModeVacance := false;
    FGeneralError := false;
    FPlaneteAdmin := false;
    FDeuteriumError := false;

    FInTable := false;
    FNextContent := pf4Neant;

    try
       FScanner.Execute;
    except
       FError := true;
    end;

    if (FPlaneteDestinationVide = false) and (FPlaneteDestinationNoobProtect = false) and (FPlaneteIsInModeVacance = false) and (FPlaneteAdmin = false) and (FDeuteriumError = false) then begin
       if FFlotteDepart.Position < 1 then
          FError := true;

       if FFlotteArrivee.Position < 1 then
          FError := true;



    end else
       FError := false;


    Result := NoT(FError);

    Unlock;
end;







////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
// Flotte 3 - Choix de l'ordre et des ressources

constructor TParsingFlotte3_OrdreEtRessources.Create(Scanner: TEasyXmlScanner);
begin
    inherited Create(Scanner);

    FListOrdreDispo := TStringList.Create;
end;

destructor TParsingFlotte3_OrdreEtRessources.Destroy;
begin
    FListOrdreDispo.Free;

    inherited Destroy;
end;

function TParsingFlotte3_OrdreEtRessources.ExistOrdre: boolean;
begin
   Result := FListOrdreDispo.Count > 0;
end;

function TParsingFlotte3_OrdreEtRessources.ExistThisOrdre(Ordre: string): boolean;
var i: integer;
begin


   // L'ordre est un nombre inférieur à 10 et supérieur à 0
   i := FListOrdreDispo.IndexOf(Ordre);

   if i >= 0 then
      Result := true
   else
      Result := false;
      

end;

procedure TParsingFlotte3_OrdreEtRessources.SetURLOfThisPage(Valeur: string);
begin
    FPageToPost  := sHTML_Get_URL_Lien(Valeur, FPageToPost);

    inherited SetURLOfThisPage(Valeur);
end;

procedure TParsingFlotte3_OrdreEtRessources.ScanOnStartTag(Sender: TObject; TagName: string; Attributes: TAttrList);
var CurrBalise: string;
begin

    TagName := lowercase(TagName);

    if TagName = 'form' then begin
       // <form action="flottenversand.php?session=1111111" method="POST">

       CurrBalise := Attributes.Value('action');

       FPageToPost := CurrBalise;
       FInForm := true;

    end else if FInForm and (TagName = 'input') then begin
        // <input name="thisgalaxy" type="hidden" value="4" />

        CurrBalise := trim(Attributes.Value('type'));

        if SameText(CurrBalise, 'hidden') then begin
           CurrBalise := Attributes.Value('name') + '=' + Attributes.Value('value');

           if FDataToPost = '' then
              FDataToPost := CurrBalise
           else
              FDataToPost := FDataToPost + '&' + CurrBalise;


           CurrBalise := Attributes.Value('name');


           if SameText(CurrBalise, 'thisresource1') then begin
              // Metal
              FCurrentRessource.Metal := StrToIntDef(Attributes.Value('value'), -1);

           end else if SameText(CurrBalise, 'thisresource2') then begin
              // Cristal
              FCurrentRessource.Cristal := StrToIntDef(Attributes.Value('value'), -1);

           end else if SameText(CurrBalise, 'thisresource3') then begin
              // Deuterium
              FCurrentRessource.Deuterium := StrToIntDef(Attributes.Value('value'), -1);

           end;



        end else if (CurrBalise = '') or (SameText(CurrBalise, 'text')) then begin
           // Simple inputbox
           // On saisie normalement les ressources désirées
           // Il y a que trois inputbox de ce type:
           // <input name="resource1" type="text" alt="Métal " size="10" onChange="calculateTransportCapacity();" />
           // <input name="resource2" type="text" alt="Cristal " size="10" onChange="calculateTransportCapacity();" />
           // <input name="resource3" type="text" alt="Deuterium " size="10" onChange="calculateTransportCapacity();" />

           if FDataToPost = '' then begin
              // Il y a obligatoirement déjà quelque chose dans FDataToPost
              FError := true;
              exit;
           end;

           CurrBalise := Attributes.Value('name');

           if SameText(CurrBalise, 'resource1') then begin
              FDataToPost := FDataToPost + '&' + CurrBalise + '=' + CNT_FLOTTE3_IN_METAL;

           end else if SameText(CurrBalise, 'resource2') then begin
              FDataToPost := FDataToPost + '&' + CurrBalise + '=' + CNT_FLOTTE3_IN_CRISTAL;

           end else if SameText(CurrBalise, 'resource3') then begin
              FDataToPost := FDataToPost + '&' + CurrBalise + '=' + CNT_FLOTTE3_IN_DEUTERIUM;

           end else begin
              // Input box inconnu...
              // On déclenche une erreur au lieu de la laisser à sa valeur par défaut
              FError := true;

           end;



        end else if SameText(CurrBalise, 'radio') then begin
           // Sélection de l'ordre
           // <input type="radio" name="order" value="3">Transport
           // <input type="radio" name="order" value="1">Attaquer

           if FDataToPost = '' then begin
              // Il y a obligatoirement déjà quelque chose dans FDataToPost
              FError := true;
              exit;
           end;

           CurrBalise := Attributes.Value('name');

           if SameText(CurrBalise, 'order') then begin

              if FRadioDejaTraiter = false then begin
                 FDataToPost := FDataToPost + '&' + CurrBalise + '=' + CNT_FLOTTE3_IN_ORDRE;
                 FRadioDejaTraiter := true;
              end;

              // Indique que cet ordre est disponible
              CurrBalise := trim(Attributes.Value('value'));

              if CurrBalise <> '' then
                 FListOrdreDispo.Add(CurrBalise);

           end else begin
              // radio inconnu
              // On déclenche une erreur
              FError := true;

           end;

        end;

    end;



end;

procedure TParsingFlotte3_OrdreEtRessources.ScanOnEndTag(Sender: TObject; TagName: string);
begin
    TagName := lowercase(TagName);

    if TagName = 'form' then begin
       FInForm := false;

    end;

end;

procedure TParsingFlotte3_OrdreEtRessources.ScanOnContent(Sender: TObject; Content: string);
begin
    // Pas de content à traiter
end;


function TParsingFlotte3_OrdreEtRessources.ParseBuffer(const Tampon: string): boolean;
begin
    Lock;

    inherited ParseBuffer(Tampon);


    FInForm := false;
    FDataToPost := '';
    FPageToPost := '';

    FRadioDejaTraiter := false;


    // Ressources actuelles
    FCurrentRessource.Metal := -1;
    FCurrentRessource.Cristal := -1;
    FCurrentRessource.Deuterium := -1;
    FCurrentRessource.Energie := 0;

    FListOrdreDispo.Clear;

    try
       FScanner.Execute;
    except
       FError := true;
    end;

    if (FCurrentRessource.Metal < 0) or (FCurrentRessource.Cristal < 0) or (FCurrentRessource.Deuterium < 0) then
       FError := true;


    Result := NoT(FError);
    Unlock;
    
end;







////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
// Flotte 2 - Choix de la destination

procedure TParsingFlotte2_ChoixDestination.SetURLOfThisPage(Valeur: string);
begin
    FPageToPost  := sHTML_Get_URL_Lien(Valeur, FPageToPost);

    inherited SetURLOfThisPage(Valeur);
end;


procedure TParsingFlotte2_ChoixDestination.ScanOnStartTag(Sender: TObject; TagName: string; Attributes: TAttrList);
var CurrBalise: string;
begin

    TagName := lowercase(TagName);

    if TagName = 'form' then begin
       // <form action="flotten3.php?session=00000000" method="POST">

       CurrBalise := Attributes.Value('action');

       FPageToPost := CurrBalise;
       FInForm := true;
       
    end else if FInForm and (TagName = 'input') then begin
        // <input name="thisgalaxy" type="hidden" value="4" />

        CurrBalise := trim(Attributes.Value('type'));

        if SameText(CurrBalise, 'hidden') then begin
           CurrBalise := Attributes.Value('name') + '=' + Attributes.Value('value');

           if FDataToPost = '' then
              FDataToPost := CurrBalise
           else
              FDataToPost := FDataToPost + '&' + CurrBalise;


           CurrBalise := Attributes.Value('name');

           if SameText(CurrBalise, 'speedfactor') then begin
              // Le problème est que l'on ne sait pas si c'est un entier ou un flottant
              // Pour l'instant on vérifie juste si il est bien égale à 1
              FSpeedFactor := trim(Attributes.Value('value'));

              (*
              if FSpeedFactor <> '1' then
                 FError := true;
              *)


           end;


        end else if CurrBalise = '' then begin
           // Simple inputbox
           // On saisie normalement les coordonnées de la planète cible dedans
           // Il y a que trois inputbox de ce type:
           // <input name="galaxy" size="3" maxlength="2" onChange="shortInfo()" onKeyUp="shortInfo()" value="4" />
           // <input name="system" size="3" maxlength="3" onChange="shortInfo()" onKeyUp="shortInfo()" value="173" />
           // <input name="planet" size="3" maxlength="2" onChange="shortInfo()" onKeyUp="shortInfo()" value="6" />

           if FDataToPost = '' then begin
              // Il y a obligatoirement déjà quelque chose dans FDataToPost
              FError := true;
              exit;
           end;

           CurrBalise := Attributes.Value('name');

           if SameText(CurrBalise, 'galaxy') then begin
              FDataToPost := FDataToPost + '&' + CurrBalise + '=' + CNT_FLOTTE2_IN_GALAXYCIBLE;

           end else if SameText(CurrBalise, 'system') then begin
              FDataToPost := FDataToPost + '&' + CurrBalise + '=' + CNT_FLOTTE2_IN_SYSTEMCIBLE;

           end else if SameText(CurrBalise, 'planet') then begin
              FDataToPost := FDataToPost + '&' + CurrBalise + '=' + CNT_FLOTTE2_IN_PLANETPOSCIBLE;

           end else begin
              // Input box inconnu...
              // On déclenche une erreur au lieu de la laisser à sa valeur par défaut
              FError := true;

           end;

        end;

        
    end else if FInForm and (TagName = 'select') then begin
        // Il y a deux select:
        //    celui pour la vitesse
        // et celui pour le type de la cible (lune, champs de ruine, planète)
        // <select name="planettype" onChange="shortInfo()" onKeyUp="shortInfo()">
        // <select name="speed" onChange="shortInfo()" onKeyUp="shortInfo()">

        if FDataToPost = '' then begin
           // Il y a obligatoirement déjà quelque chose dans FDataToPost
           FError := true;
           exit;
        end;

        CurrBalise := Attributes.Value('name');

        if SameText(CurrBalise, 'planettype') then begin
           FDataToPost := FDataToPost + '&' + CurrBalise + '=' +  CNT_FLOTTE2_IN_CIBLETYPE;

        end else if SameText(CurrBalise, 'speed') then begin
           FDataToPost := FDataToPost + '&' + CurrBalise + '=' +  CNT_FLOTTE2_IN_SPEEDRATIO;

        end else begin
           // Select inconnu... Nouvelle version du formulaire probablement ?
           // On déclenche une erreur
           FError := true;
        end;
        
    end;

    

end;

procedure TParsingFlotte2_ChoixDestination.ScanOnEndTag(Sender: TObject; TagName: string);
begin

    TagName := lowercase(TagName);

    if TagName = 'form' then begin
       FInForm := false;

    end;

end;

procedure TParsingFlotte2_ChoixDestination.ScanOnContent(Sender: TObject; Content: string);
begin
    // On a jamais besoin d'une chaine string de la page
end;

function TParsingFlotte2_ChoixDestination.ParseBuffer(const Tampon: string): boolean;
begin
    Lock;

    inherited ParseBuffer(Tampon);


    FInForm := false;
    FDataToPost := '';
    FPageToPost := '';

    try
       FScanner.Execute;
    except
       FError := true;
    end;

    Result := NoT(FError);
    Unlock;
end;










////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
// Flotte 1 - Choix vaisseaux

(*
procedure TParsingFlotte1_ChoixVaisseaux.SetURLOfThisPage(Valeur: string);
begin
    if FURLToPostChoixVaisseaux <> '' then
       FURLToPostChoixVaisseaux  := sHTML_Get_URL_Lien(Valeur, FURLToPostChoixVaisseaux);

    FFlotteList.SetURLOfPage(Valeur);

    inherited SetURLOfThisPage(Valeur);
end;

function TParsingFlotte1_ChoixVaisseaux.GetKeyNameGID(KeyName: string; var KeySansLeGID: string): integer;
var lng, xPos: integer;
begin

    // Tout les id des vaisseaux sont compris entre 200 et 299 (donc commence par un 2)
    // Ceci dit, on pourrait aussi identifié l'id de manière plus classique

    KeySansLeGID := '';
    lng := length(KeyName);

    if lng <= 4 then exit;

    // Le nombre tient sur 3 chiffres et est en fin de chaine
    KeySansLeGID := copy(KeyName, 1, lng - 3);
    System.Delete(KeyName, 1, lng - 3);

    Result := StrToIntDef(KeyName, -1);
    


end;

procedure TParsingFlotte1_ChoixVaisseaux.AddHidden(KeyName, Value: string);
var kGID: integer;
    KeySansLeGID: string;
begin

   kGID := GetKeyNameGID(KeyName, KeySansLeGID);

   if kGID <= 0 then exit;


   if FCurrentVaisseau.GID <= 0 then begin
      FCurrentVaisseau.GID := kGID;

   end else begin
      // Vérifie sinon si le gid correspond à celui actuel
      if FCurrentVaisseau.GID <> kGID then begin
         // Erreur fatale
         FError := true;
         exit;
      end;

   end;

{   <tr height="20">
    <th><a title="Vitesse: 15000">Grand transporteur</a></th>
    <th>29<input type="hidden" name="maxship203" value="29"/></th>
<!--    <th>15000 -->
     <input type="hidden" name="consumption203" value="50"/>
     <input type="hidden" name="speed203" value="15000" /></th>
     <input type="hidden" name="capacity203" value="25000" /></th>
     <th><a href="javascript:maxShip('ship203');" >max</a> </th>
     <th><input name="ship203" size="10" value="0" alt="Grand transporteur 29"/></th>
   </tr>
}


   if SameText(KeySansLeGID, 'maxship') then begin
      FCurrentVaisseau.Max := StrToIntDef(Value, -1);

   end else if SameText(KeySansLeGID, 'consumption') then begin
      FCurrentVaisseau.Consomation := StrToIntDef(Value, -1);

   end else if SameText(KeySansLeGID, 'speed') then begin
      FCurrentVaisseau.Speed := StrToIntDef(Value, -1);

   end else if SameText(KeySansLeGID, 'capacity') then begin
      FCurrentVaisseau.Capacite := StrToIntDef(Value, -1);

   end;

   if FCurrentVaisseau.AllHiddenInput = '' then
      FCurrentVaisseau.AllHiddenInput := KeyName + '=' + Value
   else
      FCurrentVaisseau.AllHiddenInput := FCurrentVaisseau.AllHiddenInput + '&' + KeyName + '=' + Value;

end;


procedure TParsingFlotte1_ChoixVaisseaux.ScanOnStartTag(Sender: TObject; TagName: string; Attributes: TAttrList);
var CurrBalise, CurrXX: string;
    sMisc: string;
    sGID: integer;
begin


    TagName := lowercase(TagName);

    if TagName = 'form' then begin
       // Pour le formulaire de choix des vaisseaux:
       //<form action="flotten2.php?session=0000000000" method="POST">

       // Pour le bouton de retour de flotte dans la liste des flottes:
       //<form action="flotten1.php?session=0000000000" method="POST">

       CurrBalise := Attributes.Value('action');
       FInForm := true;


       if FInWhat = fsiwVaisseauChoix then begin
          FURLToPostChoixVaisseaux := CurrBalise;

       end else begin
          FFormulaireCountHidden := 0;

          if FFormulaireRetourFound then begin
             FInForm := false;
          end else begin
             FCurrentFlotte.ReturnDataURL := CurrBalise;
          end;
       end;



    end else if TagName = 'a' then begin
       FLastABaliseTitle := Attributes.Value('title');


    end else if TagName = 'table' then begin
       FCurrTableLigne   := 0;
       FCurrTableColonne := 0;

       // fsiwListDesFlottes



    end else if TagName = 'tr' then begin
       Inc(FCurrTableLigne);
       FCurrTableColonne := 0;


       if FInWhat = fsiwVaisseauChoix then begin
          if IsValidVaisseau then begin
             // Ajoute le vaisseau dans la liste
             FVaisseauxList.Add(FCurrentVaisseau);
          end;

          InitVaisseau;

       end else if FInWhat = fsiwListDesFlottes then begin

          if IsValidFlotte then begin
             FFlotteList.Add(FCurrentFlotte);
          end;

          InitFlotte;
       end;

    end else if (TagName = 'td') or (TagName = 'th') then begin
       Inc(FCurrTableColonne);


    end else if TagName = 'input' then begin
       // <input type="hidden" name="consumption203" value="50"/>


       CurrBalise := lowercase(Attributes.Value('type'));


       if FInWhat = fsiwVaisseauChoix then begin

          if SameText(CurrBalise, 'hidden') then begin

             AddHidden(Attributes.Value('name'), Attributes.Value('value'));


          end else if CurrBalise = '' then begin
             // simple input box, c'est à dire le champs où l'on saisie le nombre
             // de vaisseaux que l'on veut utiliser

             sGID := GetKeyNameGID(Attributes.Value('name'), sMisc);

             if FCurrentVaisseau.GID = sGID then begin
                // Ok, cela correspond

                if SameText(sMisc, 'ship') then begin
                   // Ok, bonne valeur
                   // Rempli le champ, il faut 0 par défaut
                   FCurrentVaisseau.InputNameForChoix := Attributes.Value('name') + '=';

                end;

             end;


          end else if SameText(CurrBalise, 'submit') then begin
              // Le bouton submit existe, sinon cela signifie que l'on a atteint le
              // nb de flotte maxi
              // Il ne peut pas être confondu avec un autre bouton submit de retour
              // de flotte car on est toujours dans le if FInWhat = fsiwVaisseauChoix
              FBoutonSubmitExist := true;

          end;


       end else if FInWhat = fsiwListDesFlottes then begin

          if FCurrentFlotte.Numero > 0 then begin

             if FInForm then begin


                if SameText(CurrBalise, 'hidden') then begin
                   // A présent, il se peut qu'il y ai deux FORM
                   // pour une flotte
                   // - Une FORM pour le groupement de flotte
                   // - Une FORM pour le retour de flotte
                   //
                   // Il faut identifier la bonne form...
                   //

                   Inc(FFormulaireCountHidden);

                   if FFormulaireRetourFound then begin

                      if FFormulaireCountHidden > 1 then begin
                         // Erreur, car il y a qu'un seul champ
                         // dans le formulaire retour
                         FCurrentFlotte.ReturnDataToPost := '';
                         FError := true;

                      end else begin
                         // FFormulaireCountHidden = 1
                         // C'est un autre formulaire qui vient de commencer
                         // celui du groupement
                         FFormulaireCountHidden := 0;
                      end;
                   end;

                   CurrXX := Attributes.Value('name');

                   if SameText('order_return', CurrXX) then begin
                      // formulaire de retour de flotte
                      FFormulaireRetourFound := true;

                      FCurrentFlotte.ReturnDataToPost := CurrXX + '=' + Attributes.Value('value');
                   end;


                end; // hidden

             end; // in form
          end; // numero de flotte
       end; // fsiwListDesFlottes



    end;


end;

procedure TParsingFlotte1_ChoixVaisseaux.ScanOnEndTag(Sender: TObject; TagName: string);
begin
    TagName := lowercase(TagName);

    if TagName = 'table' then begin

       if FInWhat = fsiwListDesFlottes then begin
          // La prochaine table correspondra au choix des flottes
          if IsValidFlotte then begin
             FFlotteList.Add(FCurrentFlotte);
          end;
          InitFlotte;

          FInWhat := fsiwVaisseauChoix;
       end;


    end else if TagName = 'form' then begin
       FInForm := false;

    end;

end;

procedure TParsingFlotte1_ChoixVaisseaux.TraiteContentVaisseauxList(Content: string);
begin

    if FCurrTableLigne < 2 then exit;

    case FCurrTableColonne of
        1: begin
              FCurrentVaisseau.GIDNom := Content;

           end;

        // Tout les autres champs se récupère grâce aux input hidden
    end;


end;


procedure TParsingFlotte1_ChoixVaisseaux.TraiteContentFlotteList(Content: string);
begin

    if FCurrTableLigne < 3 then exit;

    if Content = '' then exit;

    case FCurrTableColonne of
        1: begin
                // Numero
                // <th>1</th>
                FCurrentFlotte.Numero := StrToIntDef(Content, -1);
           end;

        2: begin
                // Mission
                //  <a title="">Transporter</a>
                //  <a title="Aller">(A)</a>

                if (Content[1] = '(') and (length(Content) > 1) then begin
                   Content := lowercase(Content);



                   if Content[2] = LangParsing.GetDataChar('flotte1_cmplw_SensAller', 'a') then begin
                      FCurrentFlotte.Direction := odAller;

                   end else if Content[2] = LangParsing.GetDataChar('flotte1_cmplw_SensRetour', 'r') then begin
                      FCurrentFlotte.Direction := odRetour;

                   end else begin
                      // inconnu
                      FError := true;
                   end;


                end else begin
                    // Transporter
                    FCurrentFlotte.Mission := mamOrdreStrToType(Content);

                    // Ressource dans: FLastABaliseTitle
                    // FCurrentFlotte.Ressource :=

                end;

           end;

        3: begin
               // Nombre
               // <a title="Petit transporteur: 1">1</a>
               FCurrentFlotte.Nombre    := StrToIntDef(Content, -1);
               FCurrentFlotte.Vaisseaux := FLastABaliseTitle;

           end;

        4: begin
               // Depart
               FCurrentFlotte.Depart := mpcExtractPlanetLocation(Content);

           end;
        5: begin
               // Depart date
               // Thu Nov 24 16:28:36
               FCurrentFlotte.DepartDate := OGDATETIME_StrToUnix(Content);

           end;

        6: begin
               // Arrivee
               FCurrentFlotte.Arrivee := mpcExtractPlanetLocation(Content);

           end;
        7: begin
               // Arrivee date
               // Thu Nov 24 17:31:16
               FCurrentFlotte.ArriveeDate := OGDATETIME_StrToUnix(Content);

               if FCurrentFlotte.ArriveeDate < FCurrentFlotte.DepartDate then begin
                  // l'année doit être différente
                  FCurrentFlotte.ArriveeDate := OGDATETIME_StrToUnix(Content, ThisYear + 1);
               end;

           end;

    end;


end;



procedure TParsingFlotte1_ChoixVaisseaux.ScanOnContent(Sender: TObject; Content: string);
var xPos: integer;
begin


    case FInWhat of
        fsiwNeant: begin
                   // Le passage à la liste des flottes correspond à
                   // <td colspan="8" class="c">Flottes (max. 11)</td>

    {$IFDEF OFFICIER_OK}
                   if FFlotteAmiralDeFlotte then begin
                      if SameText(Content, '+2') then begin
                         FFlotteMax := FFlotteMax + 2;
                         FInWhat := fsiwListDesFlottes;
                         InitFlotte;
                      end;

                      exit;
                   end;
    {$ENDIF}

                   if (FCurrTableLigne <> 1) and (FCurrTableColonne <> 1) then exit;

                   Content := lowercase(trim(Content));



                   if pos(LangParsing.GetData('flotte1_lwpos_Flottes(Max', 'flottes (max'), Content) = 1 then begin
                      // Début de la liste des flottes
                      // "flottes (max. 5)"
                      xPos := LastDelimiter(' ', Content);
                      if xPos = 0 then exit;

                      System.Delete(Content, 1, xPos);

                      // "5)"
                      xPos := pos(')', Content);
                      if xPos = 0 then begin
                         // compte officier probablement
                         // car: Flottes (max. 4 <b><font style="color:lime;">+2</font></b>

                         FFlotteMax := StrToIntDef(Content, -65);

                         if FFlotteMax > 0 then begin
                            FFlotteAmiralDeFlotte := true;
                         end;


                         exit;
                      end;

                      System.Delete(Content, xPos, maxint);

                      // "5" ou "5+2"
                      xPos := pos('+', Content);

                      if xPos > 0 then begin
                         // compte officier
                         // "flottes (max. 5+2)"
                         System.Delete(Content, xPos, maxint);
                         FFlotteMax := StrToIntDef(Content, -65);
                         FFlotteMax := FFlotteMax + 2;

                      end else begin
                         // "flottes (max. 5)"
                         FFlotteMax := StrToIntDef(Content, -1);

                      end;


                      if FFlotteMax < 1 then begin
                         // erreur
                         exit;
                      end;

                      // sinon tout a réussit
                      // change l'état
                      FInWhat := fsiwListDesFlottes;
                      InitFlotte;

                   end;
                end;


        fsiwListDesFlottes: begin
                     TraiteContentFlotteList(trim(Content));

                end;

                
        fsiwVaisseauChoix: begin
                     TraiteContentVaisseauxList(trim(Content));
                end;



    end;


end;


function TParsingFlotte1_ChoixVaisseaux.ParseBuffer(const Tampon: string): boolean;
begin

    Lock;

    inherited ParseBuffer(Tampon);

    FInWhat := fsiwNeant;
    InitVaisseau;
    InitFlotte;

    
    FFlotteMax  := -1;
    FFlotteUsed := -1;

    // Attention: Il existe d'autre formulaire pour le retour de flotte
    FURLToPostChoixVaisseaux := '';


    FVaisseauxList.Clear;
    FFlotteList.Clear;
    FBoutonSubmitExist := false;


    try
      FScanner.Execute;
    except
      FError := true;
    end;
    
    if FFlotteMax <= 0 then
       FError := true;

    FFlotteUsed := FFlotteList.Count;

    if FBoutonSubmitExist = false then begin
       // Réinitialise l'url
       FURLToPostChoixVaisseaux := '';
    end;


    Result := NoT(FError);

    Unlock;
end;



constructor TParsingFlotte1_ChoixVaisseaux.Create(Scanner: TEasyXmlScanner);
begin
    inherited Create(Scanner);

    FVaisseauxList := TCollectionVaisseauSelInfos.Create;
    FFlotteList    := TCollectionFlotteListEnVoyage.Create;


    FTypeClass := CLASSTYPE_FLOTTE1;
end;

destructor TParsingFlotte1_ChoixVaisseaux.Destroy;
begin

    FFlotteList.Free;
    FVaisseauxList.Free;

    inherited Destroy;
end;


function TParsingFlotte1_ChoixVaisseaux.IsValidVaisseau: boolean;
begin

    if FInWhat <> fsiwVaisseauChoix then begin
       Result := false;
       exit;
    end;

    with FCurrentVaisseau do begin

       if (GID > 0) and (Max >= 0) and (Speed >= 0) and (Consomation >= 0) and (Capacite >= 0) then begin
          // Les sat solaire ont une vitesse/consomation/capacité nulle

          if AllHiddenInput <> '' then begin
             // On ne vérifie pas InputNameForChoix qui peut être vide pour les
             // satellite solaire par exemple

             Result := true;
             exit;

          end;

       end;

    end;

    // sinon
    Result := false;

end;

function TParsingFlotte1_ChoixVaisseaux.IsValidFlotte: boolean;
begin

    if FInWhat <> fsiwListDesFlottes then begin
       Result := false;
       exit;
    end;

    with FCurrentFlotte do begin

       if (Numero > 0) and (Mission <> ooNeant) and (Direction <> odNeant) then begin

          if (Depart.Galaxie > 0) and (DepartDate > 0) and (Arrivee.Galaxie > 0) and (ArriveeDate > 0) then begin
             Result := true;
             exit;
          end;

       end;

    end;

    // sinon
    Result := false;

end;

procedure TParsingFlotte1_ChoixVaisseaux.InitFlotte;
begin
    FCurrentFlotte.Numero    := -1;
    FCurrentFlotte.Mission   := ooNeant;
    FCurrentFlotte.Direction := odNeant;

    FCurrentFlotte.Nombre        := -1;
    FCurrentFlotte.Vaisseaux     := '';
    FCurrentFlotte.Ressource.Metal     := 0;
    FCurrentFlotte.Ressource.Cristal   := 0;
    FCurrentFlotte.Ressource.Deuterium := 0;
    FCurrentFlotte.Ressource.Energie   := 0;

    FCurrentFlotte.Depart.Galaxie   := -1;
    FCurrentFlotte.DepartDate       := 0;
    FCurrentFlotte.Arrivee.Galaxie  := -1;
    FCurrentFlotte.ArriveeDate      := 0;
    
    FCurrentFlotte.ReturnDataToPost := '';
    FCurrentFlotte.ReturnDataURL    := '';

    FFormulaireCountHidden          := 0;
    FFormulaireRetourFound          := false;


end;

procedure TParsingFlotte1_ChoixVaisseaux.InitVaisseau;
begin
    FCurrentVaisseau.GID := -1;
    FCurrentVaisseau.GIDNom := '';
    FCurrentVaisseau.Max := -1;
    FCurrentVaisseau.Speed := -1;
    FCurrentVaisseau.Consomation := -1;
    FCurrentVaisseau.Capacite := -1;
    FCurrentVaisseau.AllHiddenInput := '';
    FCurrentVaisseau.InputNameForChoix := '';
    
    FCurrentVaisseau.QuantiteVoulu := 0;


end;
*)



////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
// Galaxie



// Fonction obsolete avec la nouvelle version de la galaxy
// Champ de ruines M:0,K:1.800
procedure TParsingGalaxie.ExtractRuinesInfoFromStr(s: string);
var s2: string;
    xPos: integer;
begin

    s := trim(s);

    // Verification basique
    xPos := pos('ruines', lowercase(s));
    if xPos = 0 then exit;

    xPos := LastDelimiter(' ', s);

    if xPos = 0 then exit;
    System.Delete(s, 1, xPos);


    s := sfcRemplace(s, '.', '');

    // M:0,K:1.800
    s2 := sfcTokenGet(s, 1, ',');
    FCurrentPlanete.Ruines.Metal := sfcTokenGetInt(s2, 2, ':', -1);

    s2 := sfcTokenGet(s, 2, ',');
    FCurrentPlanete.Ruines.Cristal := sfcTokenGetInt(s2, 2, ':', -1);

end;

// Fonction obsolete avec la nouvelle version de la galaxy
// Lune S:8831,T:15
procedure TParsingGalaxie.ExtractLuneInfoFromStr(s: string);
var s2: string;
    xPos: integer;
begin

    s := trim(s);

    // Verification basique
    xPos := pos('lune', lowercase(s));
    if xPos = 0 then exit;

    xPos := pos(' ', s);

    if xPos = 0 then exit;
    System.Delete(s, 1, xPos);


    s := sfcRemplace(s, '.', '');
    
    // S:8831,T:15
    s2 := sfcTokenGet(s, 1, ',');
    FCurrentPlanete.Lune.Surface := sfcTokenGetInt(s2, 2, ':', -1);

    s2 := sfcTokenGet(s, 2, ',');
    FCurrentPlanete.Lune.Temperature := sfcTokenGetInt(s2, 2, ':', maxint);


    if FCurrentPlanete.Lune.Temperature = maxint then begin
       // echec, la temperature pouvant etre negative, on se base sur la surface
       // pour s assurer que la lune existe
       FCurrentPlanete.Lune.Surface := -1;

    end;



end;


procedure TParsingGalaxie.InitPlanete;
begin

   
   FCurrentPlanete.Location.Position := -1;

   // Nom de la planète
   FCurrentPlanete.NomPlanete     := '';

   // Nom du joueur
   FCurrentPlanete.Joueur  := '';

   // Alliance du joueur
   FCurrentPlanete.Alliance:= '';


   FCurrentPlanete.Lune.Surface := -1;
   FCurrentPlanete.Lune.Temperature := maxint;

   FCurrentPlanete.Ruines.Metal   := 0;
   FCurrentPlanete.Ruines.Cristal := 0;

   // Il y a jamais de deuterium dans les ruines
   FCurrentPlanete.Ruines.Deuterium := 0;
   FCurrentPlanete.Ruines.Energie   := 0;

   FCurrentPlanete.Position := -1;
   FCurrentPlanete.HaveToBeUpdatedFixed := true;

   FCurrentPlanete.Flags := 0;

end;






procedure TParsingGalaxie.CheckAndAjoutCurrent;
begin

    if FCurrentPlanete.Location.Position > 0 then begin

       if (FCurrentPlanete.Joueur = '') and (FCurrentPlanete.NomPlanete = '') and (FCurrentPlanete.Alliance = '') then begin
          // Planète non colonisée
          sfcFlagsAdd(CNT_GALAXIE_FLAGS_PLANETE_NON_OCCUPEE, FCurrentPlanete.Flags);
       end;


       if FDontAddPointeur = false then
          FListPlanete.Ajout(FCurrentPlanete);

    end;

    // Initialise l element
    InitPlanete;
end;


procedure TParsingGalaxie.ScanOnStartTag(Sender: TObject; TagName: string; Attributes: TAttrList);
var CurrBalise, strx, sLang: string;
    xPos: integer;
begin

   TagName := lowercase(TagName);

   if TagName = 'script' then begin
      FInScript := true;


      Inc(FScriptBaliseNum);


   end else if TagName = 'table' then begin
      FInTable := true;
      FTableLigne := 0;
      FTableColonne := 0;

   end else if TagName = 'tr' then begin
      Inc(FTableLigne);
      FTableColonne := 0;


      if FTableLigne > 2 then begin
         // Ajoute l element
         if FCurrentPlanete.Location.Position > 0 then begin

            if (FCurrentPlanete.Joueur = '') and (FCurrentPlanete.Alliance = '') then begin
               // Planète non colonisée
               sfcFlagsAdd(CNT_GALAXIE_FLAGS_PLANETE_NON_OCCUPEE, FCurrentPlanete.Flags);

               if FCurrentPlanete.NomPlanete <> '' then begin
                  // La planète vient d'être détruite
                  sfcFlagsAdd(CNT_GALAXIE_FLAGS_ASTEROIDES, FCurrentPlanete.Flags);

               end;

            end;

            if FDontAddPointeur = false then
               FListPlanete.Ajout(FCurrentPlanete);
         end;

      end;

      // Initialise l element
      InitPlanete;

   end else if (TagName = 'td') or (TagName = 'th') then begin
      Inc(FTableColonne);
      FStateColPlanete := 0;
      FInTagOption := false;

      CurrBalise := Attributes.Value('colspan');

      if (CurrBalise <> '') and (FTableLigne > 10) then begin
         // on est à la fin du tableau
         // on pourrait même arrêter le parsing
         FInTable := false;
      end;

   end else if TagName = 'font' then begin
      FInFont := true;
      FFontColor := Attributes.Value('color');

   end else if TagName = 'a' then begin
      FInLink := true;

      // On utilise FFullContent
      FFullContent := Attributes.Value('title');

      if (FInTable) and (FTableLigne >= 3) then begin

         if (FTableColonne = 4) then begin


   // <a style="cursor:pointer"
   //	onmouseover="this.T_WIDTH=250;this.T_OFFSETX=-110;this.T_OFFSETY=-110;this.T_STICKY=true;this.T_TEMP=500;
   // return escape('&lt;table width=\'240\'&gt;&lt;tr&gt;&lt;td class=\'c\' colspan=\'2\'&gt;Lune [1:4:7]&lt;/td&gt;
   // &lt;/tr&gt;&lt;tr&gt;&lt;th width=\'80\'&gt;&lt;img src=\'http://80.237.203.201/download/use/asgard/planeten/small/s_mond.jpg\'
   // height=\'75\' width=\'75\'/&gt;&lt;/th&gt;&lt;th&gt;&lt;table width=\'120\'&gt;&lt;tr&gt;&lt;td colspan=\'2\' class=\'c\'&gt;
   // Propriétés&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;th&gt;
   // Taille :&lt;/td&gt;&lt;th&gt;9544&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;th&gt;
   // Température :&lt;/td&gt;&lt;th&gt;-130&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td colspan=\'2\' class=\'c\'&gt;
   // Actions :&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;th style=\'text-align: left\' colspan=\'2\'&gt;&lt;font color=\'#808080\'&gt;Espionner&lt;/font&gt;&lt;br /&gt;&lt;br /&gt;&lt;a href=\'flotten1.php?session=0000000&galaxy=1&system=1&planet=1&planettype=3&target_mission=3\'&gt;Transporter&lt;/a&gt;&lt;br /&gt;&lt;a href=\'flotten1.php?session=000000&galaxy=2&system=1&planet=14&planettype=3&target_mission=1\'&gt;Attaquer&lt;/a&gt;&lt;br /&gt;&lt;a href=\'flotten1.php?session=000000000&galaxy=1&system=4&planet=1&planettype=3&target_mission=5\'&gt;Stationner chez un allié&lt;/a&gt;&lt;br /&gt;&lt;a href=\'flotten1.php?session=00000000&galaxy=8&system=7&planet=10&planettype=3&target_mission=9\'&gt;Détruire&lt;/a&gt;&lt;br /&gt;&lt;/th&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/th&gt;&lt;/tr&gt;&lt;/table&gt;');"
   //	>
           
           CurrBalise := Attributes.Value('onmouseover');
           CurrBalise := lowercase(CurrBalise);

           sLang := '>' + LangParsing.GetData('galaxy_lw_LuneTaille', 'taille');

           xPos := pos(sLang, CurrBalise);
           if xPos > 0 then begin
              System.Delete(CurrBalise, 1, xPos + 1);

              xPos := pos('<th>', CurrBalise);
              if xPos > 0 then begin
                 System.Delete(CurrBalise, 1, xPos + length('<th>') - 1);

                 xPos := pos('<', CurrBalise);
                 if xPos > 0 then begin
                    strx := copy(CurrBalise, 1, xPos - 1);

                    strx := sfcRemplace(strx, '.', '');
                    FCurrentPlanete.Lune.Surface := StrToIntDef(strx, -1);

                    if FCurrentPlanete.Lune.Surface > 0 then begin
                       // essaye d'extraire la temperature
                       xPos := pos(':', CurrBalise);

                       if xPos > 0 then begin
                          System.Delete(CurrBalise, 1, xPos + 1);

                          xPos := pos('<th>', CurrBalise);
                          if xPos > 0 then begin
                             System.Delete(CurrBalise, 1, xPos + length('<th>') - 1);

                             xPos := pos('<', CurrBalise);
                             if xPos > 0 then begin
                                strx := copy(CurrBalise, 1, xPos - 1);

                                strx := sfcRemplace(strx, '.', '');
                                FCurrentPlanete.Lune.Temperature := StrToIntDef(strx, -1);
                             end;

                          end;
                       end;

                    end;

                 end;

              end;
           end;



         end else if (FTableColonne = 1) then begin
            // Etrangement, juste après la position, un lien vide indique la quantité
            // de débris dans le champ de ruine... (si il existe)

            // FR:  <a href="#" title="Champ de débris : M : 0, C : 900"></a>
            // ORG: <a href="#" title="Debris field: M: 0, K: 900"></a>

            // pour reperer les champs de ruine
            // <a href="#" title="Champ de débris : M : 7.200, C : 0"></a>
            // <a href="#" title="Debris field: M: 0, K: 6.000"></a>
            CurrBalise := Attributes.Value('href');

            if CurrBalise = '#' then begin
               // FFullContent
               // clé vuegen_poslw_debris
               if pos(LangParsing.GetData('vuegen_poslw_debris', 'champ'), lowercase(FFullContent)) > 0 then begin
                  // information sur un champ de debris probable
                  xPos := pos(':', FFullContent);

                  if xPos > 0 then begin
                     System.Delete(FFullContent, 1, xPos);
                     FFullContent := trim(FFullContent);
                     FFullContent := sfcRemplace(FFullContent, '.', '');

                     xPos := pos(',', FFullContent);

                     if xPos > 0 then begin
                        strx := copy(FFullContent, 1, xPos - 1);
                        System.Delete(FFullContent, 1, xPos);

                        FCurrentPlanete.Ruines.Metal := sfcTokenGetInt(strx, 2, ':', -1);
                        FCurrentPlanete.Ruines.Cristal := sfcTokenGetInt(FFullContent, 2, ':', -1);

                        if (FCurrentPlanete.Ruines.Metal < 0) or (FCurrentPlanete.Ruines.Cristal < 0) then begin
                           // erreur...
                           FCurrentPlanete.Ruines.Metal := 0;
                           FCurrentPlanete.Ruines.Cristal := 0;
                        end;


                     end;

                  end;

               end;
            end;

         end;

      end;

   end else if TagName = 'img' then begin
      // <img src="http://xxxx/planeten/small/s_mond.jpg" height="22" width="22" alt="M Taille : 4000"/>

      if (FInTable) and (FTableLigne >= 3) then begin

         if (FTableColonne = 4) then begin
            // image de la lune certainement
            CurrBalise := Attributes.Value('src');

            xPos := LastDelimiter('/\', CurrBalise);
            if xPos < 1 then begin
               exit;
            end;
            System.Delete(CurrBalise, 1, xPos);

            if SameText(CurrBalise, 's_mond.jpg') then begin
               // lune
               CurrBalise := Attributes.Value('alt');

               xPos := pos(':', CurrBalise);
               if xPos < 1 then begin
                  exit;
               end;

               System.Delete(CurrBalise, 1, xPos);
               CurrBalise := trim(CurrBalise);

               if FCurrentPlanete.Lune.Surface < 1 then begin
                  CurrBalise := sfcRemplace(CurrBalise, '.', '');
                  FCurrentPlanete.Lune.Surface := StrToIntDef(CurrBalise, -1);
                  FCurrentPlanete.Lune.Temperature := -10000;
               end;

            end;

         end;


      end;


   end else if TagName = 'input' then begin
//<input type="hidden" name="session" value="000000000">
//<input type="hidden" id="auto" value="dr">
       CurrBalise := lowercase(Attributes.Value('type'));

       if CurrBalise = 'hidden' then begin
          CurrBalise := lowercase(Attributes.Value('name'));

          if CurrBalise = 'session' then begin
             FSessionKey := Attributes.Value('value');
          end;


       end else if (CurrBalise = 'text') or (CurrBalise = '') then begin
          CurrBalise := lowercase(Attributes.Value('name'));

          if CurrBalise = 'galaxy' then begin
             FGalaxie := StrToIntDef(Attributes.Value('value'), -1);
          end else if CurrBalise = 'system' then begin
             FSystemSolaire := StrToIntDef(Attributes.Value('value'), -1);
          end;
          
          // Champs fixe
          FCurrentPlanete.Location.Galaxie       := FGalaxie;
          FCurrentPlanete.Location.SystemSolaire := FSystemSolaire;
          FCurrentPlanete.Date := DateTimetoUnix(Now);

       end;

       FInTable := false;


   end;






end;


(*
Fonction obsolete avec la nouvelle version
procedure TParsingGalaxie.TraitementFlags(sFlags: string);
var i, lng: integer;
begin


    lng := length(sFlags);

    for i := 1 to lng do begin

       case sFlags[i] of
           'i': sfcFlagsAdd(CNT_GALAXIE_FLAGS_INACTIF_2SEMAINES, FCurrentPlanete.Flags);
           'I': sfcFlagsAdd(CNT_GALAXIE_FLAGS_INACTIF_4SEMAINES, FCurrentPlanete.Flags);
           'g': sfcFlagsAdd(CNT_GALAXIE_FLAGS_USER_BLOQUE, FCurrentPlanete.Flags);
       end;

    end;


end;
*)

procedure TParsingGalaxie.ScanOnContent(Sender: TObject; Content: string);
var xPos, xPos2: integer;
    sContent: string;
begin


  //  if NoT(FInTableauGalaxie) then exit;

    if FInScript then begin
       //FFullContent := FFullContent + ' ' + Content;
       exit;
    end;



    if FInTable then begin

        if FTableLigne < 3 then exit;

        Content := sfcRemplace(Content, '&nbsp;', ' ');
        Content := trim(Content);


         case FTableColonne of
             1: begin
                    // CITATION OBSOLETE avec la nouvelle version (73c):
                    // Position de la planete <a title="Champ de ruines M:0,K:1.800">T</a>
                    // Taille de la lune <a title="Lune S:9831,T:15">M </a>
                    // Champs de ruine

                    Content := trim(Content);
                    
                    try

                       // Il se peut que la lettre T ou M figure dans la suite
                       if FCurrentPlanete.Location.Position < 0 then
                          FCurrentPlanete.Location.Position := StrToInt(Content);

                    except
                       FCurrentPlanete.Location.Position := -1;
                    end;



                end;

             2: begin
                    // Operation sur la planète
                    // Inutile, on ignore

                end;
(*

                    end else begin
                       //  protection des noob:
                       // planetName ( <font color=a0ffa0> nick <font color=#ffffff> )
                       // Il y a des balises font dans ce cas la

                       // Mode vacances avec iI
                       //<font color= 00ff00>[SVS]</font></a> planetName ( <font color=#0000ff>nick</font>(iI) )


                       // Joueur et planete
                       // planetName ( nick )
                       // planetName ( nick(i) )

                       // Au cas où se serai un cas spécial (bloqué, mode vacance, inactif)
                       Inc(FStateColPlanete);


                       case FStateColPlanete of
                           1: begin
                                   // Premier passage (sans compter l'alliance)

                                   // Les parenthèses sont interdites dans le nom de la planète
                                   // On extrait directement le nom de la planète, il existe obligatoirement
                                   xPos := pos('(', Content);
                                   if xPos = 0 then begin
                                      if FAllowOneError = false then
                                         FError := true
                                      else
                                         FAllowOneError := false;

                                      exit;
                                   end;

                                   // Extrait le nom de la planète
                                   FCurrentPlanete.NomPlanete := trim(copy(Content, 1, xPos - 1));

                                   // Supprime le nom de la planète
                                   System.Delete(Content, 1, xPos);
                                   Content := trimleft(Content);

                                   // Maintenant, il se peut que l'on rencontre une balise font
                                   // pour un joueur noob/trop fort/en vacance
                                   // Exemple:     planetName ( <font color=#0000ff>nick</font>(iI) )
                                   // les flags (bloqué, inactif), sont toujours à l'extérieur de la balise font

                                   // Si il y a pas de balises fonts, alors
                                   // La chaine originale "planetName ( nick(i) )"
                                   // est devenu          " nick(i) )"

                                   xPos := pos(')', Content);
                                   if xPos = 0 then begin
                                      // il doit avoir une balise font
                                      exit;
                                   end;

                                   // On va supposer que les parenthèses sont interdites dans le nom du joueur
                                   xPos2 := pos('(', Content);
                                   if xPos2 > 0 then begin
                                      // Il existe des flags (iIg)
                                      FCurrentPlanete.Joueur := trim(copy(Content, 1, xPos2 - 1));

                                      System.Delete(Content, 1, xPos2);

                                      xPos := pos(')', Content);
                                      if xPos > 0 then begin
                                         System.Delete(Content, xPos, maxint);

                                         // Il ne reste plus que les flags dans Content
                                         TraitementFlags(Content);

                                      end;

                                   end else begin
                                      // pas de flags, il ne reste donc que le nom du joueur
                                      FCurrentPlanete.Joueur := trim(copy(Content, 1, xPos - 1));
                                   end;

                              end;


                           3: begin
                                   // La balise font vient de se terminer, il reste les flags
                                   // et la parenthèse de fin
                                   // planetName ( <font color=#0000ff>nick</font>(iI) )
                                   // Exemple: (iI) )
                                   // ou encore la parenthèse de fin toute seule

                                   xPos := pos('(', Content);
                                   if xPos > 0 then begin
                                      // il existe des flags, on les traite
                                      System.Delete(Content, 1, xPos);

                                      xPos := pos(')', Content);
                                      if xPos > 0 then begin
                                         System.Delete(Content, xPos, maxint);

                                         TraitementFlags(Content);
                                      end;

                                   end;

                              end;

                       end;


                    end;

                end;
*)

             3: begin
                     // Nom de la planète et activité
                     // Ex: planetName (19 min)
                     //     planetName (*)
                     //     planetName

                     xPos := LastDelimiter('(', Content);
                     if xPos > 0 then begin
                        System.Delete(Content, xPos, maxint);
                        Content := trim(Content);
                     end;

                     FCurrentPlanete.NomPlanete := Content;

                end;

             4: begin
                     // lune
                     // on extrait les informations
                     
                end;

             5: begin
                     // débris

                end;

             6: begin
                     // Joueur et Statut
                     // (<span class='inactive'>i</span> <span class='vacation'>v</span>)
                     if Content = '(' then begin
                        FInTagOption := true;

                     end else if Content = ')' then begin
                        FInTagOption := false;

                     end else begin

                        if FInTagOption then begin
                           Content := trim(content);


                           if Content = LangParsing.GetData('galaxy_joueur_fort', 'f') then begin
                              // joueur fort
                              sfcFlagsAdd(CNT_GALAXIE_FLAGS_PROTECTION_NOOB_TROPFORT, FCurrentPlanete.Flags);

                           end else if Content = LangParsing.GetData('galaxy_joueur_debutant', 'd') then begin
                              // joueur faible
                              sfcFlagsAdd(CNT_GALAXIE_FLAGS_PROTECTION_NOOB_TROPFAIBLE, FCurrentPlanete.Flags);

                           end else if Content = LangParsing.GetData('galaxy_joueur_vacance', 'v') then begin
                              // Mode vacances
                              sfcFlagsAdd(CNT_GALAXIE_FLAGS_MODE_VACANCES, FCurrentPlanete.Flags);

                           end else if Content = LangParsing.GetData('galaxy_joueur_bloque', 'b') then begin
                              // Bloqué
                              sfcFlagsAdd(CNT_GALAXIE_FLAGS_USER_BLOQUE, FCurrentPlanete.Flags);

                           end else if Content = LangParsing.GetData('galaxy_joueur_inactif2', 'i') then begin
                              // Inactif 2 semaines
                              sfcFlagsAdd(CNT_GALAXIE_FLAGS_INACTIF_2SEMAINES, FCurrentPlanete.Flags);

                           end else if Content = LangParsing.GetData('galaxy_joueur_inactif4', 'I') then begin
                              // Inactif 4 semaines
                              sfcFlagsAdd(CNT_GALAXIE_FLAGS_INACTIF_4SEMAINES, FCurrentPlanete.Flags);

                           end;



                        end else begin
                           FCurrentPlanete.Joueur := Content;
                        end;

                     end;
                     
                end;

             7: begin
                     // Alliance
                     FCurrentPlanete.Alliance := Content;
                end;

         end;


    end;


end;



procedure TParsingGalaxie.ScanOnEndTag(Sender: TObject; TagName: string);
begin
   TagName := lowercase(TagName);

   if TagName = 'script' then begin
      FInScript := false;
      FFullContent := '';


      // Ajoute l element, et le réinitialise
      CheckAndAjoutCurrent;


   end else if TagName = 'tr' then begin
      // La balise de fin de ligne n existe pas

   end else if TagName = 'font' then begin
      FInFont := false;
      FFontColor := '';

   end else if TagName = 'a' then begin
      FInLink := false;

   end;



end;





function TParsingGalaxie.ParseBuffer(const Tampon: string): boolean;
var xTampon: string;
    xPos: integer;
begin
    Lock;

    inherited ParseBuffer(Tampon);

    FInScript := false;
    FScriptBaliseNum := 0;
    FListPlanete.Clear;

    FGalaxie       := -1;
    FSystemSolaire := -1;
    FSessionKey    := '';

  //  FInTableauGalaxie := false;
    FInLink := false;

    InitPlanete;
    FError := false;
    //FAllowOneError := false;


       // initialisation pour le second parsing
       FInTable     := false;
       FTableLigne  := -1;
       FTableColonne:= -1;
       FInFont := false;

       FInScript  := false;
       FScriptBaliseNum := 0;

       FInFont := false;
       FInLink := false;
       FStateColPlanete := -1;


       FFullContent := '';
       FFontColor   := '';

       FListPlanete.Clear;

     //  FInTableauGalaxie := true;

     
    xTampon := sfcRemplace(Tampon, 'selected', 'selected="1"');
    xTampon := sfcRemplace(xTampon, ' />', '>');
    xTampon := sfcRemplace(xTampon, '/>', '>');


    // Charge le tampon
    FScanner.LoadFromBuffer(PChar(xTampon));

    try
       FScanner.Execute;
    except
       FError := true; 
    end;

    if FError then begin
       Result := false;
       exit;
    end;


    FFullContent := '';
    FFontColor   := '';

    Result := NoT(FError);
    Unlock;

end;



constructor TParsingGalaxie.Create(Scanner: TEasyXmlScanner);
begin
   inherited Create(Scanner);


   FListPlanete := TListGalaxiePlaneteSP.Create;
   FDontAddPointeur := false;
end;


destructor TParsingGalaxie.Destroy;
begin

   FListPlanete.Free;

   inherited Destroy;
end;


//procedure TParsingGalaxie.TraitementSecondeBaliseScript;
//begin
    // wrt2("11112121",2,309);

//end;



procedure GetReal(var str: string);
begin

//s=s.replace(/#1/g,'<tr><th>');
//s=s.replace(/#2/g,'</th><th>');
//s=s.replace(/#3/g,'</th>');


   str := sfcRemplace(str, '#1', '<tr><th>');
   str := sfcRemplace(str, '#2', '</th><th>');
   str := sfcRemplace(str, '#3', '</th>');


//s=s.replace(/#8/g,'<th> <a href=\"flotten.php?session=' + ss + '&fstate=3&type=Espionage&gesver2=1&ladekap2=5&s=10&c210='+a+'&ft1='+p1+'&ft2='+p2+'&ft3=');
//s=s.replace(/#9/g,'\"><img src=\"http://serveur/ogame/game/img/e.gif\" border=0 alt=\"'+a+' Envoyer la sonde\">    </a>');
//s=s.replace(/#b/g,'<a href=\"galaxy.php?session=' + ss + '&mode=1&p1='+p1+'&p2='+p2+'&ft3=');
//s=s.replace(/#c/g,'\"><img src=\"http://ogame.org/ogame/game/img/r.gif\" border=0 alt=\"Attaque de missile\">    </a>');


   str := sfcRemplace(str, '#8', '<th> <a href="flotten.php?session=<sessionkey>&fstate=3&type=Espionage&gesver2=1&ladekap2=5&s=10&c210=<param_a>&ft1=<param_p1>&ft2=<param_p2>&ft3=');
   str := sfcRemplace(str, '#9', '"><img src="http://serveur/ogame/game/img/e.gif" border=0 alt="<param_a> Envoyer la sonde"> </a>');
   str := sfcRemplace(str, '#b', '<a href="galaxy.php?session=<sessionkey>&mode=1&p1=<param_p1>&p2=<param_p2>&ft3=');
   str := sfcRemplace(str, '#c', '"><img src="http://ogame.org/ogame/game/img/r.gif" border=0 alt="Attaque de missile">  </a>');


//s=s.replace(/#4/g,'<a href=\"writemessages.php?session=' + ss + '&messageziel=');
//s=s.replace(/#5/g,'\"><img src=\"http://serveur/ogame/game/img/m.gif\" border=0 alt=\"Ecrire un message\"></a><a href=\"buddy.php?session=' + ss + '&a=2&u=');
//s=s.replace(/#X/g,'\"><img src=\"http://serveur/ogame/game/img/b.gif\" border=0 alt=\"Demande de pote\"></a>');


   str := sfcRemplace(str, '#4', '<a href="writemessages.php?session=<sessionkey>&messageziel=');
   str := sfcRemplace(str, '#5', '"><img src="http://serveur/ogame/game/img/m.gif" border=0 alt="Ecrire un message"></a><a href="buddy.php?session=<sessionkey>&a=2&u=');
   str := sfcRemplace(str, '#X', '"><img src="http://serveur/ogame/game/img/b.gif" border=0 alt="Demande de pote"></a>');


//s=s.replace(/#6/g,'</th>');
//s=s.replace(/#7/g,'<th>');
//s=s.replace(/#a/g,'</th><th></th>');

   str := sfcRemplace(str, '#6', '</th>');
   str := sfcRemplace(str, '#7', '<th>');
   str := sfcRemplace(str, '#a', '</th><th></th>');


end;

{$IFDEF DEBUGCFILE}
procedure DebugWebPage(Page: string);
var Fichier: string;
    F: TextFile;
begin

    Fichier := sfcFileGetNextNonExist('d:\ogamex.html', 4);

    AssignFile(F, Fichier);

    {$I-}
    ReWrite(F);
    {$I+}

    WriteLn(F, Page);

    CloseFile(F);

end;
{$ENDIF}

const
    CNT_SELECT_WITCHSTATS = 2;
    CNT_SELECT_TOP_LEVEL  = 3;

procedure TParsingPlayerStats.SetURLOfThisPage(Valeur: string);
var i: integer;
begin
    inherited SetURLOfThisPage(Valeur);

//    for i := 1 to 15 do
//       FLinkSwitchTop[i] := sHTML_Get_URL_Lien(Valeur, FLinkSwitchTop[i]);
end;

function TParsingPlayerStats.GetLinkTop(Index: integer): string;
begin

   Result := '';
   if Index < 1 then exit;
   if Index > 15 then exit;
   Result := FLinkSwitchTop[Index];
   
end;

procedure TParsingPlayerStats.ScanOnStartTag(Sender: TObject; TagName: string; Attributes: TAttrList);
label lTable;
var CurrBalise, sIsSelected, sTmp: string;
    xPos: integer;
begin

   TagName := lowercase(TagName);

   if TagName = 'form' then begin
      // La prochaine ouverture de balise table sera la bonne

      FInForm := true;
      exit;
   end;

   if FInForm = false then begin
      goto lTable;
   end;



   if TagName = 'select' then begin
      CurrBalise := Attributes.Value('name');

      // <select name="wer" size="1" onchange="haha(this)">
      // <select name="typ" size="1" onchange="haha(this)">
      // <select name=von size=1 onchange="haha(this)" >

      CurrBalise := lowercase(CurrBalise);

      FCanWaitForTable := true;

      if CurrBalise = 'typ' then
         FInSelect := CNT_SELECT_WITCHSTATS
      else if CurrBalise = 'von' then
         FInSelect := CNT_SELECT_TOP_LEVEL
      else
         FInSelect := -1;

   end else if TagName = 'option' then begin

      CurrBalise  := Attributes.Value('value');
      sIsSelected := Attributes.Value('selected');
      sIsSelected := trim(sIsSelected);

      if FInSelect = CNT_SELECT_WITCHSTATS then begin
//<option value="/game/stat.php?session=00000&von=0&typ=pkt" selected >Points
//<option value="/game/stat.php?session=00000&von=0&typ=flotten"  >Flottes
//<option value="/game/stat.php?session=00000&von=0&typ=forschung"  >Recherche

         sTmp := lowercase(Currbalise);

         if pos('pkt', sTmp) > 0 then begin
            FLinkSwitchPointsGeneral    := Currbalise;
            if sIsSelected = '1' then
               FLinkSwichtPointsSelected := CNT_STATSPLAYER_PGTYPE_GENERAL;

         end else if pos('flotten', sTmp) > 0 then begin
            FLinkSwitchPointsFlottes    := Currbalise;
            if sIsSelected = '1' then
               FLinkSwichtPointsSelected := CNT_STATSPLAYER_PGTYPE_FLOTTES;

         end else if pos('forschung', sTmp) > 0 then begin
            FLinkSwitchPointsRecherche  := Currbalise;
            if sIsSelected = '1' then
               FLinkSwichtPointsSelected := CNT_STATSPLAYER_PGTYPE_RECHERCHE;

         end else begin
            // Inconnu
            FError := true;
         end;

      end else if FInSelect = CNT_SELECT_TOP_LEVEL then begin
// <option value="/game/stat.php?session=0000&von=200" >201-300

          if FLinkCurrPos < 1 then begin
             // Impossible
             FError := true;
             exit;
          end;

          if FLinkCurrPos > 15 then begin
             // Indice hors limite
             FError := true;
             exit;
          end;

          FLinkSwitchTop[FLinkCurrPos] := Currbalise;

          if sIsSelected = '1' then
             FLinkSwitchTopSelected := FLinkCurrPos;

             
          Inc(FLinkCurrPos);
      end;
      
   end else if TagName = 'input' then begin
      CurrBalise  := lowercase(Attributes.Value('type'));

      if SameText(CurrBalise, 'hidden') then begin

         FFormatToUse := FFormatToUse + '&' + Attributes.Value('name') + '=' + Attributes.Value('value');
      end;

   end;



lTable:
   if FCanWaitForTable = false then exit;


   if TagName = 'table' then begin
      FInTable := true;

      FCurrTableLigne  := 0;
      FCurrTableColonne := 0;
   end;

   if FInTable = false then exit;


   if TagName = 'tr' then begin
      // Nouvelle ligne
      FCurrTableColonne := 0;
      Inc(FCurrTableLigne);


      // Réinitialise le joueur
      InitPlayer;


   end else if (TagName = 'td') or (TagName = 'th') then begin
      Inc(FCurrTableColonne);

   end;


   if (TagName = 'a') and (FCurrTableColonne = 3) then begin
      // Lien pour lui envoyer un message, et ainsi connaitre les
      // coordonnées de sa planète mère;
      // <a href="writemessages.php?session=0000000&messageziel=111111">
      CurrBalise  := lowercase(Attributes.Value('href'));

      xPos := pos('messageziel=', CurrBalise);

      if xPos = 0 then begin
         // Ils ont changé la syntaxe
         FError := true;
      end else begin
         System.Delete(CurrBalise, 1, xPos + length('messageziel=') - 1);

         FCurrentPlayer.Uid := StrToIntDef(CurrBalise, -1);

         if FCurrentPlayer.Uid < 0 then
            FError := true;
            
      end;

   end;

end;

procedure TParsingPlayerStats.ScanOnEndTag(Sender: TObject; TagName: string);
begin

    TagName := lowercase(TagName);

    if TagName = 'select' then begin
       FInSelect := -1;

    end else if TagName = 'table' then begin
       FInTable := false;

    end else if TagName = 'tr' then begin

      if (FCurrentPlayer.Place > 0) and (FCurrentPlayer.Points >= 0) and (FCurrentPlayer.Nom <> '') then begin
         // On le sauvegarde
         if FDontAddToList = false then
            FStatsList.Ajout(FCurrentPlayer);
            
         FCurrentPlayer.Place := 0;

      end;

    end;

end;

procedure TParsingPlayerStats.ScanOnContent(Sender: TObject; Content: string);
var i: integer;
begin

    // Les données sont utiles seulement si on est dans le tableau
    if FInTable = false then exit;

    // La première ligne contient l'header du tableau
    if FCurrTableLigne <= 1 then exit;


    case FCurrTableColonne of
        1: begin
               // Place;
               try
                  i := pos('&', Content);
                  if i > 0 then begin
                     System.Delete(Content, i, maxint);
                  end;

                  Content := sfcRemplace(Content, '.', '');
                  
                  if FCurrentPlayer.Place < 0 then
                     FCurrentPlayer.Place := StrToInt(Content);
                     
               except
                  FCurrentPlayer.Place := -1;
               end;

           end;
        2: begin
               // Pseudo;
               FCurrentPlayer.Nom := trim(Content);
           end;

        3: begin
               // Lien pour lui envoyer un message, et ainsi connaitre les
               // coordonnées de sa planète mère;
               // On ignore
           end;
        4: begin
               // alliance;
               FCurrentPlayer.Alliance := Trim(Content);
           end;
        5: begin
               // Nombre de points;
               try
                  Content := sfcRemplace(Content, '.', '');
                  Content := sfcRemplace(Content, ',', '');
                  FCurrentPlayer.Points := StrToInt(Content);
               except
                  FCurrentPlayer.Points := -1;
               end;
           end;

        else begin


           end;
    end;



end;
    
procedure TParsingPlayerStats.InitPlayer;
begin
   FCurrentPlayer.Place    := -1;
   FCurrentPlayer.Points   := -1;
   FCurrentPlayer.Nom      := '';
   FCurrentPlayer.Alliance := '';
   FCurrentPlayer.Uid      := 0;
end;


function TParsingPlayerStats.ParseBuffer(const Tampon: string): boolean;
var i, k: integer;
    sType: string;
    
begin
    inherited ParseBuffer(Tampon);

    FLinkSwitchPointsGeneral   := '';
    FLinkSwitchPointsFlottes   := '';
    FLinkSwitchPointsRecherche := '';
    FLinkSwichtPointsSelected  := -1;

    // indice 1: Top 100  ; Indice 2: Top 200, etc...
    for i := 1 to 15 do
       FLinkSwitchTop[i] := ''; // : array[1..15] of string;

    // Indice de la page en cours
    FLinkSwitchTopSelected := -1;

    // Sert pour le parsing car on n'utilise pas les données de OnContent
    FLinkCurrPos:= 1;



    FInSelect  := -1;

    FInTable   := false;
    FCurrTableLigne   := 0;
    FCurrTableColonne := 0;

    FCanWaitForTable := false;

    InitPlayer;

    FFormatToUse := '';

    
    FStatsList.Clear;

    // Lance le scan
    FScanner.Execute;

    sType := 'pts';
    
    case FTypeStats of
        stoPointsX   : sType := 'pts';
        stoFlottesX  : sType := 'flt';
        stoRechercheX: sType := 'res';
    end;



    // A CAUSE DE LA MISE A JOUR, on définit nous même les données
    // à poster pour aller plus vite
    FFormatToUse := 'who=player&type=%s&start=%d' + FFormatToUse;

    k := 1;
    for i := 1 to 15 do begin
       FLinkSwitchTop[i] := format(FFormatToUse, [sType, k]);
       Inc(k, 100);
    end;
    FError := false;



    for i := 1 to 15 do begin
       if FLinkSwitchTop[i] = '' then begin
          FError := true;
          break;
       end;

    end;

    Result := NoT(FError);
end;

constructor TParsingPlayerStats.Create(Scanner: TEasyXmlScanner); 
begin
    inherited Create(Scanner);

    FStatsList := TListStatsPlayerSP.Create;
    FDontAddToList := false;

    FTypeStats := stoPointsX;
end;

destructor TParsingPlayerStats.Destroy; 
begin

    FStatsList.Free;
    
    inherited Destroy;
end;





function TParsingBase.ParseBuffer(const Tampon: string): boolean;
begin

    // Redéfinit les pointeurs, car il se peut que le même parseur
    // soit utilisé pour toute les pages
    Scanneur.OnEndTag   := ScanOnEndTag;
    Scanneur.OnEmptyTag := nil;
    Scanneur.OnStartTag := ScanOnStartTag;
    Scanneur.OnContent  := ScanOnContent;

    FError := false;

end;


procedure TParsingBaseGamePage.SetDebugProc(Value: TsfcProcStatus);
begin
   inherited SetDebugProc(Value);

   {$IFDEF DEBUG}
   // la procédure de débogage correspond à la procédure de ParsingBase
   FHeaderParser.DebugProcMinerai := DoDebug;
   {$ENDIF}
end;

procedure TParsingBaseGamePage.SetURLOfThisPage(Valeur: string);
begin
    inherited SetURLOfThisPage(Valeur);
    
    FHeaderParser.AutrePlanete.SetFullURL(Valeur);
end;

function TParsingBaseGamePage.GetPlanetStr: string;
begin
    Result := FHeaderParser.PlaneteStr;
end;

function TParsingBaseGamePage.GetRessources: TOGRessourceAll;
begin
    Result := FHeaderParser.CurrRessource;
end;

function TParsingBaseGamePage.GetIsValidHeader: boolean;
begin
    Result := FHeaderParser.IsValidHeader;

    (*
    if FHeaderParser.FCurrentPlanete.Galaxie < 0 then
       Result := false
    else
       Result := true;
    *)

end;


function TParsingBaseGamePage.ParseBuffer(const Tampon: string): boolean;
var xTampon: string;
begin

    // Pas d'héritage car c'est la première fois qu'on implémente cette fonction
    // update: la fonction a finalement été implémenté dans la classe mère
    inherited ParseBuffer(Tampon);

    // Ceci permet de vérifier si la page est valide
    FHeaderParser.FCurrentPlanete.Galaxie := -1;

    xTampon := sfcRemplace(Tampon, 'selected', 'selected="1"');
    xTampon := sfcRemplace(xTampon, ' />', '>');
    xTampon := sfcRemplace(xTampon, '"/>', '">');

    xTampon := sfcRemplace(xTampon, '/>', '>');

    xTampon := sfcRemplace(xTampon, 'this.T_WIDTH=150;return escape("', '');
    xTampon := sfcRemplace(xTampon, '&lt;br&gt;")', '');
    xTampon := sfcRemplace(xTampon, '&lt;br&gt;', '; ');



    // Balise de commentaire
    //xTampon := sfcRemplace(xTampon, '<!-- ', '<invalid x="');
   // xTampon := sfcRemplace(xTampon, ' -->', '">');


    FHeaderParser.Prepare;
    FError := false;

    // Charge dès à présent le tampon
    FScanner.LoadFromBuffer(PChar(xTampon));

    Result := true;
end;

procedure TParsingBaseGamePage.OnFinHeader(Sender: TObject);
begin
    // Rétable les fonctions
    Scanneur.OnEndTag   := ScanOnEndTag;
    Scanneur.OnEmptyTag := nil;
    Scanneur.OnStartTag := ScanOnStartTag;
    Scanneur.OnContent  := ScanOnContent;

end;

procedure TParsingBase.SetDebugProc(Value: TsfcProcStatus);
begin
    {$IFDEF DEBUG}
       FDebugProc := Value;
    {$ENDIF}
end;

procedure TParsingBase.DoDebug(const Msg: string);
begin
    {$IFDEF DEBUG}
       if Assigned(FDebugProc) then begin
          FDebugProc('Parsing - ' + Msg);
       end;
    {$ENDIF}
end;

procedure TParsingBase.SetURLOfThisPage(Valeur: string);
begin
    FURLOfThisPage := Valeur;
end;

constructor TParsingBaseGamePage.Create(Scanner: TEasyXmlScanner);
begin
    inherited Create(Scanner);

    // Scanner peut être à nil, donc on utilise Self.Scanneur qui existe vraiment
    FHeaderParser := TParsingDebutDocumentMineraiAndPlanet.Create(Self.Scanneur);
    FHeaderParser.OnFinTravail := OnFinHeader;


end;

destructor TParsingBaseGamePage.Destroy;
begin
    FHeaderParser.Free;


    inherited Destroy;
end;







procedure TParsingBase.Lock;
begin
    EnterCriticalSection(FReadWriteCS);
end;

procedure TParsingBase.Unlock;
begin
    LeaveCriticalSection(FReadWriteCS);
end;

constructor TParsingBase.Create(Scanner: TEasyXmlScanner);
begin
    inherited Create;

    InitializeCriticalSection(FReadWriteCS);
    
    FScanner := Scanner;

    if FScanner = nil then begin
       FScanner := TEasyXmlScanner.Create(nil);
       FScannerCreated := true;

    end else
       FScannerCreated := false;

    Scanneur.OnEndTag   := ScanOnEndTag;
    Scanneur.OnEmptyTag := nil;
    Scanneur.OnStartTag := ScanOnStartTag;
    Scanneur.OnContent  := ScanOnContent;


    FTypeClass := CLASSTYPE_UNDEFINED;


end;


destructor TParsingBase.Destroy;
begin

    if FScannerCreated then begin
       FScanner.Free;

    end;

    DeleteCriticalSection(FReadWriteCS);

    inherited Destroy;
end;


procedure TParsingAppercu.ExtractCasesDiametre;
var xPos, i: integer;
    s: string;
begin
// 15800 km     ( <a title="Cases occupées"> 85 </a> / <a title="nombre maximal des cases utilisables">193 </a> cases )
// sans les balises et espace entre "contenu", ce qui donne:
// 15800 km     (85/193cases)


    xPos := pos('(', FTamponTraitement);
    if xPos = 0 then exit;

    System.Delete(FTamponTraitement, 1, xPos);

    xPos := pos('/', FTamponTraitement);
    if xPos = 0 then exit;

    s := copy(FTamponTraitement, 1, xPos - 1);
    FCasesOccupees := StrToIntDef(s, -1);

    if FCasesOccupees < 0 then exit;

    System.Delete(FTamponTraitement, 1, xPos);

    i := 1;
    s := '';
    while (i <= length(FTamponTraitement)) do begin
       if FTamponTraitement[i] in sfc_ChiffresSet then
          s := s + FTamponTraitement[i]
       else
          break;

       Inc(i);
    end;

    FCasesTotal := StrToIntDef(s, -1);

    FTamponTraitement := '';
end;


procedure TParsingAppercu.ExtractPointClassement(Tampon: string);
var xPos: integer;
    s: string;
begin
    // 1045 (Place 4222 de 10915)
    // 151 (Rank 6931 of 13071)
    // ATTENTION: Il se peut que l'ordre des nombres soit inversé
    // dans certain univers

    Tampon := trim(Tampon);

    xPos := pos(' ', Tampon);
    if xPos = 0 then exit;

    s := copy(Tampon, 1, xPos - 1);
    System.Delete(Tampon, 1, xPos);

    FPoints := StrToIntDef(s, -1);


    // (Place 222 de 10915)
    // (Rank 931 of 13071)
    xPos := pos(' ', Tampon);
    if (xPos = 0) or (FPoints < 0) then exit;
    System.Delete(Tampon, 1, xPos);
    Tampon  := trimleft(Tampon);

    xPos := pos(' ', Tampon);
    if (xPos = 0) then exit;
    s := copy(Tampon, 1, xPos - 1);
    System.Delete(Tampon, 1, xPos);

    FClassementPosition := StrToIntDef(s, -1);

    // de 10915)
    // of 13071)
    xPos := pos(')', Tampon);
    if (xPos = 0) or (FClassementPosition < 0) then exit;
    System.Delete(Tampon, xPos, maxint);

    xPos := LastDelimiter(' ', Tampon);
    if xPos = 0 then exit;

    s := copy(Tampon, xPos + 1, maxint);
    FClassementTotalPlayers := StrToIntDef(s, -1);

end;


destructor TParsingAppercu.Destroy;
begin

    FMessageList.Free;

    inherited Destroy;
end;


constructor TParsingAppercu.Create(Scanner: TEasyXmlScanner);
begin
    inherited Create(Scanner);

    // Rien à initialiser, mis à part ce qui est fait lorsque l'on parse les données
    FTypeClass := CLASSTYPE_APPERCU;

    FMessageList := TCollectionAppMessage.Create;
    FUseSpanClass_AND_MsgGame_If_Fail := false;

    FOverrideSpanClassOrdre := false;
    FOverrideSpanClassDirection := false;

end;


procedure TParsingAppercu.InitMsgFlotte(bDoNotResetDateEtDuree: boolean = true);
begin
    with FAppFlotteMsg do begin

         if bDoNotResetDateEtDuree then begin
            Duree      := -1;
            DateImpact := 0;
         end;

         Ordre     := ooNeant;
         Direction := odNeant;

         bColorMenace := false;
         bOwnFlotte   := false;

         PlayerFlotte := '';

         Depart.Galaxie  := -1;
         DepartStr       := '';
         Arrivee.Galaxie := -1;
         ArriveeStr      := '';

         NbVaisseau := -1;
         VaisseauxStr := '';
         Msg := '';
    end;

    FTypeMsg := -1;

end;


function TParsingAppercu.ParseBuffer(const Tampon: string): boolean;
var xTampon: string;
begin

       Lock;

       inherited ParseBuffer(Tampon);

       FCasesOccupees          := -1;
       FCasesTotal             := -1;
       FPoints                 := -1;
       FClassementPosition     := -1;
       FClassementTotalPlayers := -1;
       FCurrNomPlantet         := '';
       FCurrNomJoueur          := '';
       FDateServeur            := 0;
       FIsLune                 := false;

       FCurrAttackGroup  := 0;

       FInDataUtile      := false;
       FInTable          := 0;
       FWhatIsNextContent:= CNT_NEXT_CONTENT_UNKNOW;
       FTamponTraitement := '';

       FTable1Ligne  := -1;
       FTable1Colonne:= -1;
       FTable1ColonneSpan := -1;

       FMessageList.Clear;

       try
          FScanner.Execute;
       except
          FError := true;
       end;

       // OVERRIDDING pour la mise à jour
       FError := false;

       if FPoints < 0 then begin
          DoDebug('Erreur: Nombre de points négatif');
          FError := true;
       end;

       if FCurrNomPlantet = '' then begin
          DoDebug('Erreur: Nom de planète vide');
          FError := true;
       end;

       if FCasesTotal < 1 then begin
          // c'est une erreur

          if FCasesTotal < 0 then begin
             DoDebug('Erreur: Nombre de cases totales négatif');
             FError := true;

          end else begin
             DoDebug('Attention: Moins d''une case au total sur la planète (plus considéré comme une erreur)');
          end;


       end else if FCasesTotal < 2 then begin
          // c'est peut-être une nouvelle lune

          if pos(LangParsing.GetData('apercu_LunePosFi', 'une'), FCurrNomPlantet) <= 1 then begin
             // ce n'est pas une lune
             DoDebug('Attention: Moins de 2 cases au total sur la planète (plus considéré comme une erreur)');

             //FError := true;

          end;


       end;


       Result := NoT(FError);

       Unlock;
end;


procedure TParsingAppercu.ScanOnStartTag(Sender: TObject; TagName: string; Attributes: TAttrList);
var xPos: integer;
    CurrBalise: string;
begin

    TagName := lowercase(TagName);

    if (FInDataUtile = false) and (TagName = 'a') then begin
        // Les données utiles commencent à partir du nom de la planète
        // A ce moment là, on est alors dans une "table"

        // <a href="renameplanet.php?session=000000&pl=777777" title="Planetenmenü">Planète      &quot;PlaneteNom&quot;</a> (PseudoJoueur)
        // FInDataUtile
        CurrBalise := trim(Attributes.Value('href'));

        // TODO: Sauvegarder ce lien pour permettre le changement de nom de
        // la planète
        CurrBalise := lowercase(CurrBalise);

        if pos('renameplanet', CurrBalise) > 0 then begin
            FInDataUtile := true;

            // et on est donc dans une table
            // ceci n'est plus un boolean car il y a une autre table
            // dans la table
            FInTable := 1;
            FTable1Ligne := 1;

            FWhatIsNextContent := CNT_NEXT_CONTENT_PLANETNAME;
        end;

        exit;
    end;

    if FInDataUtile = false then exit;

    // On ignore les tableaux qui sont inclu dans le tableau utile
    if FInTable > 1 then exit;


    if TagName = 'table' then begin
       Inc(FInTable);


    end else if TagName = 'tr' then begin
       if FWhatIsNextContent = CNT_NEXT_CONTENT_IN_DIAMETRE_BUF then begin
          // Réinitialise le flag
          FWhatIsNextContent := CNT_NEXT_CONTENT_UNKNOW;

          // Traite le tampon
          ExtractCasesDiametre;
       end;


       Inc(FTable1Ligne);
       FTable1Colonne := 0;


       if FThisLigneIsFlotte  and (FAppFlotteMsg.Duree > 0) and (FAppFlotteMsg.Ordre <> ooNeant) and (FAppFlotteMsg.Msg <> '') then begin
          // Message de flotte à gérer
          FMessageList.Add(FAppFlotteMsg);
       end;
       FThisLigneIsFlotte := false;
       InitMsgFlotte;
       FTamponTraitement := '';
       FInFont := false;

       
       FCurrAttackGroup := 0;






    end else if (TagName = 'td') or (TagName = 'th') then begin
       Inc(FTable1Colonne);

       CurrBalise := trim(Attributes.Value('colspan'));

       if CurrBalise = '' then
          FTable1ColonneSpan := 0
       else
          FTable1ColonneSpan := StrToIntDef(CurrBalise, 0);


    end else if TagName = 'div' then begin
       // <div id="bxx1"  title="1204" star="1127805762"></div>

       // Début de mouvement de flotte
       CurrBalise := trim(Attributes.Value('title'));

       if (CurrBalise <> '') and (sfcChaineContientQueDesChiffres(CurrBalise)) then begin
          FThisLigneIsFlotte := true;

          try
             FAppFlotteMsg.Duree := StrToInt(CurrBalise);
          except
             FThisLigneIsFlotte := false;
          end;

          FContentPos := 0;
       end;


       // DateImpact
       //
       CurrBalise := trim(Attributes.Value('star'));
       if FThisLigneIsFlotte and (CurrBalise <> '') and (sfcChaineContientQueDesChiffres(CurrBalise)) then begin
           // il semble que c'est l'heure d'impact sur le serveur
           // c'est d'ailleurs excellent

          try
             FAppFlotteMsg.DateImpact := StrToInt(CurrBalise);
          except
             FAppFlotteMsg.DateImpact := 0;
          end;


       end;



    end else if TagName = 'font' then begin


       if FThisLigneIsFlotte then begin
          FInFont := true;

          CurrBalise := lowercase(trim(Attributes.Value('color')));

          // Ennemi: #ff0000  abrégeable en #ff
          // Ami: #00ff00

       (*
          if copy(CurrBalise, 1, 3) = '#ff' then begin
             FAppFlotteMsg.bColorMenace := true;

          end else if copy(CurrBalise, 1, 5) = '#00ff' then begin
             FAppFlotteMsg.bColorMenace := false;

          end else begin
             FThisLigneIsFlotte := false;
          end;
*)
          
       end;
       
    end else if TagName = 'a' then begin

       // messages
       CurrBalise := trim(Attributes.Value('href'));
       FAClass := trim(Attributes.Value('class'));


       FTitleBaliseA := trim(Attributes.Value('onmouseover'));

       // TODO: Sauvegarder ce lien pour permettre le changement de nom de
       // la planète
       CurrBalise := lowercase(CurrBalise);

        if pos('messages', CurrBalise) > 0 then begin

            if FThisLigneIsFlotte = false then
               FWhatIsNextContent := CNT_NEXT_CONTENT_NEWMESSAGE;

        end;


    end else if TagName = 'br' then begin

       if FCurrAttackGroup > 0 then begin
          Inc(FCurrAttackGroup);
       end;

    end else if TagName = 'span' then begin
        // <span class='flight attack'>
        FSpanClass := trim(Attributes.Value('class'));

        if FCurrAttackGroup > 2 then begin
           // c'est bien une attaque groupee

           if FThisLigneIsFlotte  and (FAppFlotteMsg.Duree > 0) and (FAppFlotteMsg.Ordre <> ooNeant) and (FAppFlotteMsg.Msg <> '') then begin
              // Message de flotte à gérer
              FMessageList.Add(FAppFlotteMsg);
           end;

           InitMsgFlotte(false);
           FTamponTraitement := '';
           FInFont := false;

           FContentPos := 0;

           // Ce parametre n'est pas reinitialise à false
           FThisLigneIsFlotte := true;


        end;

    end else if TagName = 'script' then begin


    end;


    // renameplanet

end;

procedure TParsingAppercu.ScanOnEndTag(Sender: TObject; TagName: string);
begin

    // Ici on ne met pas la condition FInTable > 1, car on attend justement
    // la fin de la table pour continuer, on la met donc plus loin
    if FInDataUtile = false then exit;

    TagName := lowercase(TagName);


    if TagName = 'table' then begin
       Dec(FInTable);


       //FWhatIsNextContent := CNT_NEXT_CONTENT_UNKNOW;
       
       if FInTable = 0 then begin
          // On a finit le travail
          FScanner.StopParser := true;
          exit;
       end;

    end else if TagName = 'a' then begin
       FTitleBaliseA := '';
       

    end else if TagName = 'font' then begin
       FInFont := false;


    end;

    // Condition qui attend la fin de la table avant de continuer
    if FInTable > 1 then exit;


end;


function GetVaisseauxStrFromJS(const MsgJS: string; var NbVaisseaux: integer): string;
var xPos: integer;
begin
// <a href='#' onmouseover='
// this.T_WIDTH=150;return escape("Nombre
//de vaisseaux : 138 &lt;br&gt;Petit transporteur 16&lt;br&gt;Grand transporteur 42&lt;br&gt;Chasseur
//léger 20&lt;br&gt;Chasseur lourd 31&lt;br&gt;Croiseur 20&lt;br&gt;Vaisseau de bataille 10&lt;br&gt;")'
//class='attack'>

    Result := MsgJS;



    (*
    xPos := pos('"', Result);
    if xPos = 0 then begin
       Result := 'Erreur';
       exit;
    end;
    System.Delete(Result, 1, xPos);


    xPos := pos('"', Result);
    if xPos = 0 then begin
       Result := 'Erreur';
       exit;
    end;
    System.Delete(Result, xPos, maxint);
    *)

    xPos := pos(':', Result);
    if xPos > 0 then begin
       // contient le nombre de vaisseaux
       System.Delete(Result, 1, xPos);
       Result := trimleft(Result);
       NbVaisseaux := sfcTokenGetInt(Result, 1, ' ', -1);

       xPos := pos(';', Result);
       if xPos > 0 then
          System.Delete(Result, 1, xPos);

    end;

    Result := sfcRemplace(Result, '&lt;br&gt;', '; ');
    Result := sfcRemplace(Result, '<br>', '; ');
    Result := sfcRemplace(Result, '<br />', '; ');
    Result := trim(Result);

end;


(*
procedure TParsingAppercu.GestionMsgAutreJoueur(Content: string);
var xPos: integer;
begin

// se rapproche de la planète planetName[4:1:6] Cette flotte est composée de 5 Vaisseauxs. ( 5*Grand transporteur) Son ordre est: Transport
// ou
// se rapproche de la planète planetName[7:10:1] Cette flotte est composée de 184 Vaisseauxs. ( 4*Grand transporteur, 180*Vaisseau de bataille) Son ordre est: Attaquer

   xPos := pos('de la plan', Content);
   if xPos = 0 then begin
      FError := true;
      exit;
   end;
   System.Delete(Content, 1, xPos + length('de la plan'));

   xPos := pos(' ', Content);
   if xPos = 0 then begin
      FError := true;
      exit;
   end;
   System.Delete(Content, 1, xPos);

   xPos := pos('[', Content);
   if xPos = 0 then begin
      FError := true;
      exit;
   end;


   FAppFlotteMsg.ArriveeStr := trim(copy(Content, 1, xPos - 1));

   System.Delete(Content, 1, xPos);

   // 7:10:1] Cette flotte est composée de 184 Vaisseauxs. ( 4*Grand transporteur, 180*Vaisseau de bataille) Son ordre est: Attaquer

   xPos := pos(']', Content);
   if xPos = 0 then begin
      FError := true;
      exit;
   end;
   
   FAppFlotteMsg.Arrivee := mpcExtractPlanetLocation(copy(Content, 1, xPos - 1));

   System.Delete(Content, 1, xPos);


   xPos := pos(' de ', Content);
   if xPos = 0 then begin
      FError := true;
      exit;
   end;

   System.Delete(Content, 1, xPos + length(' de ') - 1);


   // 184 Vaisseauxs. ( 4*Grand transporteur, 180*Vaisseau de bataille) Son ordre est: Attaquer
   xPos := pos(' ', Content);
   if xPos = 0 then begin
      FError := true;
      exit;
   end;

   FAppFlotteMsg.NbVaisseau := StrToIntDef(copy(Content, 1, xPos - 1), -1);

   xPos := pos('(', Content);
   if xPos = 0 then begin
      FError := true;
      exit;
   end;
   System.Delete(Content, 1, xPos);

   xPos := pos(')', Content);

   FAppFlotteMsg.VaisseauxStr := trim(copy(Content, 1, xPos - 1));

   System.Delete(Content, 1, xPos);

   // Son ordre est: Attaquer
   xPos := pos(':', Content);
   if xPos = 0 then begin
      FError := true;
      exit;
   end;
   System.Delete(Content, 1, xPos);

   // Attaquer, Transport, ou encore Espionnage
   FAppFlotteMsg.Ordre := mamOrdreStrToType(Content);

end;
*)




function VerificationIsMoon(PetitePartieDuMsg: string): boolean;
var xPos: integer;
begin

    Result := false;

    // les parentheses sont interdites dans un nom de planete
    // quand il y a des parentheses, c'est pour indiquer que c'est une lune
    // cependant, cela n'est valable uniquement si la planete a ete renomme
    xPos := pos('(', PetitePartieDuMsg);

    if xPos > 0 then begin
       // Dans ce cas là on est certain
       Result := true;

    end else begin
       // on essaye la version habituelle sinon
       // ATTENtiON: cela ne suffit pas, car une planete peut porter le nom "Lune"
       xPos := pos(LangParsing.GetData('vuegen_poslw_lune', 'lune ['), Lowercase(PetitePartieDuMsg));

       if xPos > 0 then begin
          // Verification supplementaire qui consiste à verifier si le mot
          // "planete" n'existe pas dans la phrase
          // on aurait alors "la planète Lune ["

          xPos := pos(LangParsing.GetData('vuegen_poslw_planete', 'plan'), Lowercase(PetitePartieDuMsg));

          if xPos > 0 then begin
             // c'est une planète
             Result := False;

          end else begin
             // c'est bien une lune
             Result := True;
          end;

       end else begin
          // on est certain que ce n'est pas une lune
          Result := false;
       end;

    end;


end;


///////////////////////////////////////////////////
// L'attaque/sondage (rating comme ennemi)
// mais aussi le transport pacifique
// car ils ont le meme format de message
//
// La methode de parsing a été amelioré pour supporter facilement
// plusieurs langue (on supprime directement un nombre de mot précis au
// lieu de rechercher si un mot existe puis de le supprimer)
//
function TParsingAppercu.GestionMsgFlotteAutreJoueur(Content: string): boolean;
var sPart: string;
    xPos: integer;
    bIsFromLune, bLocalErreur: boolean;

    DataStr: string;
    DataInt: integer;
begin


    // Pacifique ou allié, le message reste le même car
    // il y a un lien pour envoyer un message ingame au joueur
    // et on utilise le texte qui se situe après ce lien
    // il y a un problème si jamais le mot "pacifique"
    // ou "ennemi" se situe après ce lien.
    // pour l'univers fr, us et es ce n'est pas le cas.

    //ennemy: venant de la planète PlanetName [6:33:1] atteint la planète PlanetName [6:4:15]. Elle avait pour mission: Attaquer</span>
    //ennemy: venant de la Lune [1:89:4] atteint la Lune [1:265:5]. Elle avait pour mission: Attaquer</span>
    //  ally: venant de la planète Planete [3:1:6] atteint la planète Kingdom [3:13:14]. Elle avait pour mission: Transporter

    //  ally: from planet PlanetName [5:1:12] is approaching planet PlanetName [5:18:9]. Its mission is: Transport.
    //ennemy: from planet PlanetName [5:113:8] is approaching planet PlanetName [5:139:9]. Its mission is: Attack.

    //ennemy: de el planeta PlanetName [4:99:6] llega a el planeta PlanetName [1:7:10]. La misión es: Atacar
    //  ally: de el planeta PlanetName [4:99:6] llega a el planeta PlanetName [1:7:10]. La misión es: Transportar

    //////////////////////////////////:
    // REMARQUE: cette parti du parsing ne sert à rien car
    // l'interet est d'avoir les coordonnées, ou plus exactement,
    // savoir que l'on est attaqué et connaitre la durée de l'impact
    // suffit largement pour le robot.
    // Tout le reste (sauf les coordonnées d'impact) est inutile (surtout
    // les noms de planete où l'on se casse la tête pour les trouver)
    // Seul le fait de savoir si c'est une lune ou pas la planete de destination
    // est interessant.

    ///////////////////////////////////////
    // REMARQUE 2:
    // Avec la nouvelle methode d'identificaton de lune, on ne verifie
    // pas si le mot planete existe. Un joueur malin peut donc faire
    // croire qu'il attaque d'une lune sans en avoir.
    // MAIS cela n'est pas important car le but est d'effectuer
    // l'évacuation de flotte, pas de contre attaquer ^^
    // cependant, c'est assez génant.
    

    bIsFromLune := false;
    bLocalErreur := false;
    Result := false;


    xPos := pos('[', Content);
    if xPos = 0 then  begin
       FError := true;
       exit;
    end;

    // inclu le [
    sPart := copy(Content, 1, xPos);
    System.Delete(Content, 1, xPos);


    // Extrait le nom de la planète de départ (celle du joueur adverse)
    // on commence par verifier si ce n'est pas une lune
    //xPos := pos(LangParsing.GetData('vuegen_poslw_lune', 'lune ['), Lowercase(sPart));



    if VerificationIsMoon(sPart) then begin
       // lune
       FAppFlotteMsg.DepartStr := LangParsing.GetData('Lune', 'Lune');
       bIsFromLune := true;

    end else begin
       // Sinon c'est à partir d'une planète
       // il n'y a que le sens aller pour les flottes ennemies/pacifiques
       // venant de la planète scout171 [5:87:4]
       DataStr := LangParsing.GetData('vuegeneral_ennflotte_msg_aller_premier', '5');

       try
          DataInt := StrToInt(DataStr);
       except
          DataInt := maxint;
       end;

       if DataInt = maxint then begin
          // erreur du fichier langue
          // ce n'est pas une erreur de parsing
          // on essaie de corriger l'erreur...
          FError := true;
          bLocalErreur := true;
          DataInt := 2;
       end;


       // extrait le nom de la planete
       DataInt := -1 * DataInt;
       sPart := sfcTokenGet(sPart, DataInt, ' ');

       // Supprime le " ["
       System.Delete(sPart, length(sPart) - 1, maxint);

       FAppFlotteMsg.DepartStr := trim(sPart);

       if bLocalErreur then
          FAppFlotteMsg.DepartStr := FAppFlotteMsg.DepartStr + LANG_PLANET_PARSING_ADD_INVALID;

    end;

    xPos := pos(']', Content);
    if xPos = 0 then  begin
       FError := true;
       exit;
    end;

    // extrait les coordonnées
    FAppFlotteMsg.Depart := mpcExtractPlanetLocation(copy(Content, 1, xPos - 1));

    if bIsFromLune then begin
       FAppFlotteMsg.Depart.Position := FAppFlotteMsg.Depart.Position + CNT_POSITION_LUNE;
    end;
    System.Delete(Content, 1, xPos);
    Content := trimleft(Content);


    ///////////////////////////////////////////////////:
    // Planete cible
    //
    bIsFromLune := false;
    bLocalErreur := false;

    xPos := pos('[', Content);
    if xPos = 0 then begin
       FError := true;
       exit;
    end;

    // inclu le [
    sPart := copy(Content, 1, xPos);
    System.Delete(Content, 1, xPos);


    //xPos := pos(LangParsing.GetData('vuegen_poslw_lune', 'lune ['), Lowercase(sPart));

    if VerificationIsMoon(sPart) then begin
       FAppFlotteMsg.ArriveeStr := LangParsing.GetData('Lune', 'Lune');
       bIsFromLune := true;

    end else begin
       // Sinon c'est à partir d'une planète

       DataStr := LangParsing.GetData('vuegeneral_ennflotte_msg_aller_second', '4');

       try
          DataInt := StrToInt(DataStr);
       except
          DataInt := maxint;
       end;

       if DataInt = maxint then begin
          // erreur du fichier langue
          // ce n'est pas une erreur de parsing
          // on essaie de corriger l'erreur...
          FError := true;
          bLocalErreur := true;
          DataInt := 2;
       end;


       // extrait le nom de la planete
       DataInt := -1 * DataInt;
       sPart := sfcTokenGet(sPart, DataInt, ' ');

       // Supprime le " ["
       System.Delete(sPart, length(sPart) - 1, maxint);

       FAppFlotteMsg.ArriveeStr := trim(sPart);

       if bLocalErreur then
          FAppFlotteMsg.ArriveeStr := FAppFlotteMsg.ArriveeStr + LANG_PLANET_PARSING_ADD_INVALID;

    end;

    xPos := pos(']', Content);
    if xPos = 0 then  begin
       FError := true;
       exit;
    end;

    // extrait les coordonnées
    FAppFlotteMsg.Arrivee  := mpcExtractPlanetLocation(copy(Content, 1, xPos - 1));

    if bIsFromLune then begin
       FAppFlotteMsg.Arrivee.Position := FAppFlotteMsg.Arrivee.Position + CNT_POSITION_LUNE;
    end;
    System.Delete(Content, 1, xPos);
    Content := trimleft(Content);

    

    Result := true;


    ///////////////////////////////
    // Extrait la mission

    if (FAppFlotteMsg.Ordre = ooNeant) or FOverrideSpanClassOrdre then begin
       // la mission n'a pas été détecté à partir du SPAN class
       // Content = ". Elle avait pour mission: Attaquer"
       xPos := pos(':', Content);
       if xPos = 0 then  begin
          FError := true;
          exit;
        end;

        System.Delete(Content, 1, xPos);
        Content := trim(Content);
        
        FAppFlotteMsg.Ordre := mamOrdreStrToType(Content);

        if mamIsAttackGroupee(Content) then begin
           // c'est une attaque groupee
           FCurrAttackGroup := 1;
        end;
    end;

end;



///////////////////////////////////////////////////
// Tous les messages de nos propres flottes
//
// La methode de parsing a été amelioré pour supporter facilement
// plusieurs langue (on supprime directement un nombre de mot précis au
// lieu de rechercher si un mot existe puis de le supprimer)
//
function TParsingAppercu.GestionMsgFlotteLaNotre(Content: string): boolean;
var DefineIsRetour: string;
    DataStr: string;
    DataInt: integer;

    bLocalErreur: boolean;

    xPos: integer;
    sPart: string;
    bIsFromLune: boolean;
    bIsFromDebris: boolean;
begin
    // venant de la planète p1 [9:6:7] atteint la  lune [9:4:3]. Elle avait pour mission:
    // venant de la planète p2 [1:2:3] atteint la planète p3 [4:5:6]. Elle avait pour mission:

    // rentre de la  Champ de débris [5:5:9] à la  lune [5:5:5]. Elle avait pour mission:
    // rentre de la planète p3 [4:5:6] à la planète p4 [4:5:7]. Elle avait pour mission:

    Result := false;

    if (FAppFlotteMsg.Direction = odNeant) or FOverrideSpanClassDirection then begin
       DefineIsRetour := LangParsing.GetData('vuegen_known_retour_method', 'r');
       DataStr        := LangParsing.GetData('vuegen_known_retour_data', 'rentre de la');

       if pos(DataStr, Content) > 0 then begin
          if SameText(DefineIsRetour, 'r') then
             FAppFlotteMsg.Direction := odRetour
          else
             FAppFlotteMsg.Direction := odAller;

       end else begin
          if SameText(DefineIsRetour, 'r') then
             FAppFlotteMsg.Direction := odAller
          else
             FAppFlotteMsg.Direction := odRetour;
       end;
    end;


    ///////////////////////////////////
    // ATTENTION:
    // En français "venant de la" et "rentre de la"
    // tienne sur un même nombre de mot, MAIS ce n'est peut-être
    // pas le cas pour les autres langue
    // En espagnol:
    // de el planeta PlanetName [3:123:12] llega a el planeta PlanetName [3:9:4]. La misión es:
    // vuelve de el planeta PlanetName [3:9:4] a el planeta PlanetName [3:123:12]. La misión era:
    //
    // On a 2 mots pour l'aller, et 3 pour le retour.
    ////////////////////////////////////

    xPos := pos('[', Content);

    // conserve le ]
    sPart := copy(Content, 1, xPos);
    System.Delete(Content, 1, xPos);




    // on commence par verifier si ce n'est pas une lune
(*
    // les parentheses sont interdites dans un nom de planete
    // quand il y a des parentheses, c'est pour indiquer que c'est une lune
    // cependant, cela n'est valable uniquement si la planete a ete renomme
    xPos := pos(LangParsing.GetData('('), Lowercase(sPart));

    if xPos = 0 then begin
       // on essaye la version habituelle sinon
       // ATTENtiON: cela ne suffit pas, car une planete peut porter le nom "Lune"
       xPos := pos(LangParsing.GetData('vuegen_poslw_lune', 'lune ['), Lowercase(sPart));
    end;
*)


    bIsFromLune   := false;
    bIsFromDebris := false;
    bLocalErreur  := false;

    if VerificationIsMoon(sPart) then begin
       // c'est une lune
       FAppFlotteMsg.DepartStr := LangParsing.GetData('Lune', 'Lune');
       bIsFromLune := true;

    end else begin
       // maintenant il se peut que c'est un champ de débris
       if FAppFlotteMsg.Ordre = ooExploiter then begin
          if FAppFlotteMsg.Direction = odAller then begin
             // le mot "champ de debris" apparaitra dans le champ "planete d'arriver"

          end else begin
             // le mot "champ  de debris" doit correspond au champ actuel
             // on effectue une simple verification
             xPos := pos(LangParsing.GetData('vuegen_poslw_debris', 'champ'), Lowercase(sPart));
             if xPos > 0 then begin
                FAppFlotteMsg.DepartStr := LangParsing.GetData('vuegen_affiche_debris', 'Champ de débris');
                bIsFromDebris := true;
             end;

          end;
       end;

       if bIsFromDebris = false then begin
          // Sinon c'est à partir d'une planète



          if FAppFlotteMsg.Direction = odAller then
             // venant de la planète PlanetName [
             DataStr := LangParsing.GetData('vuegeneral_ownflotte_msg_aller_premier', '5')

          else
             // rentre de la planète PlanetName [
             DataStr := LangParsing.GetData('vuegeneral_ownflotte_msg_retour_premier', '5');

          try
             DataInt := StrToInt(DataStr);
          except
             DataInt := maxint;
          end;

          if DataInt = maxint then begin
             // erreur du fichier langue
             // ce n'est pas une erreur de parsing
             // on essaie de corriger l'erreur...
             FError := true;
             bLocalErreur := true;
             DataInt := 2;
          end;

          DataInt := -1 * DataInt;
          sPart := sfcTokenGet(sPart, DataInt, ' ');

          // Supprime le " ["
          System.Delete(sPart, length(sPart) - 1, maxint);

          FAppFlotteMsg.DepartStr := trim(sPart);

          if bLocalErreur then
             FAppFlotteMsg.DepartStr := FAppFlotteMsg.DepartStr + LANG_PLANET_PARSING_ADD_INVALID;

       end;

    end;


    xPos := pos(']', Content);
    if xPos = 0 then  begin
       FError := true;
       exit;
    end;

    // extrait les coordonnées
    FAppFlotteMsg.Depart := mpcExtractPlanetLocation(copy(Content, 1, xPos - 1));

    if bIsFromLune then begin
       FAppFlotteMsg.Depart.Position := FAppFlotteMsg.Depart.Position + CNT_POSITION_LUNE;
    end else if bIsFromDebris then begin
       // on devrait ajouter quelque chose ?

    end;

    System.Delete(Content, 1, xPos);
    Content := trimleft(Content);



    ///////////////////////////////////////////////////:
    // Planete cible
    //

    // atteint la  lune [5:5:5]. Elle avait pour mission:
    // à la  lune [5:5:5]. Elle avait pour mission:
    // à la planète p1 [4:5:6]. Elle avait pour mission:
    // a el planeta PlanetName [3:2:1]. La misión era:
    
    xPos := pos('[', Content);

    // conserve le [
    sPart := copy(Content, 1, xPos);
    System.Delete(Content, 1, xPos);

    // on commence par verifier si ce n'est pas une lune
    //xPos := pos(LangParsing.GetData('vuegen_poslw_lune', 'lune ['), Lowercase(sPart));

    bIsFromLune   := false;
    bIsFromDebris := false;
    bLocalErreur  := false;



    if VerificationIsMoon(sPart) then begin
       // c'est une lune
       FAppFlotteMsg.ArriveeStr := LangParsing.GetData('Lune', 'Lune');
       bIsFromLune := true;

    end else begin
       // maintenant il se peut que c'est un champ de débris
       if FAppFlotteMsg.Ordre = ooExploiter then begin
          if FAppFlotteMsg.Direction = odRetour then begin
             // le mot "champ de debris" a du apparaitre dans le champ "planete de depart"

          end else begin
             // le mot "champ  de debris" doit correspondre au champ actuel
             // on effectue une simple verification

             xPos := pos(LangParsing.GetData('vuegen_poslw_debris', 'champ'), lowercase(sPart));
             if xPos > 0 then begin
                FAppFlotteMsg.ArriveeStr := LangParsing.GetData('vuegen_affiche_debris', 'Champ de débris');
                bIsFromDebris := true;
             end;

          end;
       end;

       if bIsFromDebris = false then begin
          // Sinon elle atteint une planète


          if FAppFlotteMsg.Direction = odAller then
             // atteint la planète planetName [
             DataStr := LangParsing.GetData('vuegeneral_ownflotte_msg_aller_second', '4')

          else
             // à la planète planetName
             DataStr := LangParsing.GetData('vuegeneral_ownflotte_msg_retour_second', '4');


          try
             DataInt := StrToInt(DataStr);
          except
             DataInt := maxint;
          end;

          if DataInt = maxint then begin
             // erreur du fichier langue
             // ce n'est pas une erreur de parsing
             // on essaie de corriger l'erreur...
             FError  := true;
             bLocalErreur := true;
             DataInt := 2;
          end;

          DataInt := -1 * DataInt;
          sPart := sfcTokenGet(sPart, DataInt, ' ');

          // Supprime le " ["
          System.Delete(sPart, length(sPart) - 1, maxint);

          FAppFlotteMsg.ArriveeStr := trim(sPart);

          if bLocalErreur then
             FAppFlotteMsg.ArriveeStr := FAppFlotteMsg.ArriveeStr + LANG_PLANET_PARSING_ADD_INVALID;

       end;

    end;


    xPos := pos(']', Content);
    if xPos = 0 then  begin
       FError := true;
       exit;
    end;


    // extrait les coordonnées
    FAppFlotteMsg.Arrivee := mpcExtractPlanetLocation(copy(Content, 1, xPos - 1));

    if bIsFromLune then begin
       FAppFlotteMsg.Arrivee.Position := FAppFlotteMsg.Arrivee.Position + CNT_POSITION_LUNE;
    end else if bIsFromDebris then begin
       // on devrait ajouter quelque chose ?

    end;

    System.Delete(Content, 1, xPos);
    Content := trimleft(Content);



    Result := true;


    ///////////////////////////////
    // Extrait la mission

    if (FAppFlotteMsg.Ordre = ooNeant) or FOverrideSpanClassOrdre then begin
       // la mission n'a pas été détecté à partir du SPAN class
       // Content = ". Elle avait pour mission: Attaquer"
       xPos := pos(':', Content);
       if xPos = 0 then  begin
          // la mission est probablement dans le OnContent suivant
          exit;
        end;

        System.Delete(Content, 1, xPos);
        Content := trim(Content);
        
        FAppFlotteMsg.Ordre := mamOrdreStrToType(Content);
    end;

end;


procedure TParsingAppercu.ScanOnContent(Sender: TObject; Content: string);
var xPos: integer;
    lngPos: integer;

    ContentTrimLw, Content1: string;
    bIsFromLune: boolean;

    bChecked: boolean;
begin



    if pos(LangParsing.GetData('apercu_lwpos_heure_serveur', 'heure du serveur'), lowercase(Content)) > 0 then begin
       if FInDataUtile = false then begin
          // on était alors sur une lune
          FCurrNomPlantet := LangParsing.GetData('Lune', 'Lune');
          FIsLune := true;
          FInDataUtile := true;
          FInTable := 1;
          FTable1Ligne := 2;
          FWhatIsNextContent := CNT_NEXT_CONTENT_SERVER_TIME;
          exit;
       end;

    end;

    if FInDataUtile = false then exit;
    if FInTable > 1 then exit;


    if FThisLigneIsFlotte then begin

       Inc(FContentPos);




       if FContentPos = 1 then begin
          // Sauvegarde le texte
          FAppFlotteMsg.Msg := Content;
          FNotFromSpanChecked := false;

          // Met en minuscule la chaine
          ContentTrimLw := lowercase(trim(Content));


          /////////////////////////////////////////////////////
          // PROPRE FLOTTE - DEBUT
          /////////////////////////////////////////////////////
          bChecked := false;

          if  SameText(FSpanClass, APERCU_SPAN_CLASS_OWN_TRANSPORT)        then begin
              FAppFlotteMsg.Ordre      := ooTransport;
              FAppFlotteMsg.Direction  := odAller;
              bChecked := true;

          end else if SameText(FSpanClass, APERCU_SPAN_CLASS_OWN_TRANSPORT_RETOUR) then begin
              FAppFlotteMsg.Ordre      := ooTransport;
              FAppFlotteMsg.Direction  := odRetour;
              bChecked := true;



          end else if SameText(FSpanClass, APERCU_SPAN_CLASS_OWN_STATIONNER)        then begin
              FAppFlotteMsg.Ordre      := ooBaser;
              FAppFlotteMsg.Direction  := odAller;
              bChecked := true;

          end else if SameText(FSpanClass, APERCU_SPAN_CLASS_OWN_STATIONNER_RETOUR) then begin
              FAppFlotteMsg.Ordre      := ooBaser;
              FAppFlotteMsg.Direction  := odRetour;
              bChecked := true;



          end else if SameText(FSpanClass, APERCU_SPAN_CLASS_OWN_RECYCLAGE)        then begin
              FAppFlotteMsg.Ordre      := ooExploiter;
              FAppFlotteMsg.Direction  := odAller;
              bChecked := true;

          end else if SameText(FSpanClass, APERCU_SPAN_CLASS_OWN_RECYCLAGE_RETOUR) then begin
              FAppFlotteMsg.Ordre      := ooExploiter;
              FAppFlotteMsg.Direction  := odRetour;
              bChecked := true;



          end else if SameText(FSpanClass, APERCU_SPAN_CLASS_OWN_ESPIONAGE)        then begin
              FAppFlotteMsg.Ordre      := ooEspionner;
              FAppFlotteMsg.Direction  := odAller;
              bChecked := true;

          end else if SameText(FSpanClass, APERCU_SPAN_CLASS_OWN_ESPIONAGE_RETOUR) then begin
              FAppFlotteMsg.Ordre      := ooEspionner;
              FAppFlotteMsg.Direction  := odRetour;
              bChecked := true;



          end else if SameText(FSpanClass, APERCU_SPAN_CLASS_OWN_ATTAQUE)        then begin
              FAppFlotteMsg.Ordre      := ooAttaquer;
              FAppFlotteMsg.Direction  := odAller;
              bChecked := true;

          end else if SameText(FSpanClass, APERCU_SPAN_CLASS_OWN_ATTAQUE_RETOUR) then begin
              FAppFlotteMsg.Ordre      := ooAttaquer;
              FAppFlotteMsg.Direction  := odRetour;
              bChecked := true;



          end else if SameText(FSpanClass, APERCU_SPAN_CLASS_OWN_COLONISATION)        then begin
              FAppFlotteMsg.Ordre      := ooColoniser;
              FAppFlotteMsg.Direction  := odAller;
              bChecked := true;

          end else if SameText(FSpanClass, APERCU_SPAN_CLASS_OWN_COLONISATION_RETOUR) then begin
              FAppFlotteMsg.Ordre      := ooColoniser;
              FAppFlotteMsg.Direction  := odRetour;
              bChecked := true;




          end else if FUseSpanClass_AND_MsgGame_If_Fail or (FSpanClass = '')  then begin
              // determine à partir du message


              if SameText(ContentTrimLw, LangParsing.GetData('apercu_st_une_de_vos', 'Une de vos')) or SameText(ContentTrimLw, LangParsing.GetData('apercu_st_une_de_tes', 'Une de tes')) then begin
                 FAppFlotteMsg.Ordre      := ooNeant;
                 FAppFlotteMsg.Direction  := odNeant;
                 bChecked := true;
                 FNotFromSpanChecked := true;
              end;

          end;

// Francais:
// <span class='flight owntransport'>Une de tes <a href='#' onmouseover='this.T_WIDTH=150;return escape("Petit transporteur 56&lt;br&gt;Grand transporteur 90&lt;br&gt;")' class='owntransport'>flottes</a><a href='' title='Petit transporteur 56Grand transporteur 90'></a> venant de la planète PlanetName [7:7:5] atteint la  lune [5:265:5]. Elle avait pour mission: <a href='#' onmouseover='this.T_WIDTH=150;return escape("Transporter: &lt;br /&gt; Métal: 1500000&lt;br /&gt;Cristal: 500000&lt;br /&gt;Deutérium: 10000")' class='owntransport'>Transporter</a><a href='#' title='Transporter: Métal: 1500000 Cristal: 500000 Deutérium: 10000'></a></span>
// Anglais:
// <span class='flight owntransport'>One of your <a href='#' onmouseover='this.T_WIDTH=150;return escape("Small Cargo 1&lt;br&gt;")' class='owntransport'>fleets</a><a href='' title='Small Cargo 1'></a> from planet PlanetName [5:1:2] reaches planet PlanetName [4:1:9]. Its mission is: Transport.</span>
// Espagnol:
// <span class="flight owntransport">Una de tus <a href="#" onmouseover='this.T_WIDTH=150;return escape("Sonda de espionaje 4<br>")' class="owntransport">flotas</a><a href="" title="Sonda de espionaje 4"></a> de el planeta PlanetName [3:4:5] llega a el planeta Hathor [3:9:4]. La misión es: <a href="#" onmouseover='this.T_WIDTH=150;return escape("Transportar: <br /> Metal: 3000<br />Cristal: 3000<br />Deuterio: 7000")' class="owntransport">Transportar</a><a href="#" title="Transportar: Metal: 3000 Cristal: 3000 Deuterio: 7000"></a></span>


          if bChecked then begin
             // Action avec ses propres flottes
             FAppFlotteMsg.bOwnFlotte := true;
             FAppFlotteMsg.bColorMenace := false;

             FTypeMsg := CNT_FLOTTE_TYPEMSG_TRANSPORTPLANETE_ALLER;
             exit;
          end;






          /////////////////////////////////////////////////////
          // ENNEMI FLOTTE HOSTILE - DEBUT
          // Attaque ou sondage
          /////////////////////////////////////////////////////

          bChecked := false;
          if SameText(FSpanClass, APERCU_SPAN_CLASS_ENNEMI_ATTACK) then begin
             // verifié par la class d'affichage de couleur
             FAppFlotteMsg.Ordre := ooAttaquer;
             bChecked := true;


          end else if SameText(FSpanClass, APERCU_SPAN_CLASS_ENNEMI_ATTACK_GROUP) then begin
             // verifié par la class d'affichage de couleur
             FAppFlotteMsg.Ordre := ooAttaquer;
             FCurrAttackGroup := 1;
             bChecked := true;


          end else if SameText(FSpanClass, APERCU_SPAN_CLASS_ENNEMI_SPYING) then begin
             // verifié par la class d'affichage de couleur
             FAppFlotteMsg.Ordre := ooEspionner;
             bChecked := true;


          end else if FUseSpanClass_AND_MsgGame_If_Fail or (FSpanClass = '')  then begin

             if SameText(ContentTrimLw, LangParsing.GetData('apercu_lw_ennemi_flotte', 'une')) then begin
                FAppFlotteMsg.Ordre := ooNeant;
                bChecked := true;
                FNotFromSpanChecked := true;
             end;

          end;

// Français (attaque):
// <span class='flight attack'>Une <a href='#' onmouseover='this.T_WIDTH=150;return escape("Nombre de vaisseaux: 1666 &lt;br&gt;Chasseur léger 1666&lt;br&gt;")' class='attack'>flotte</a><a href='' title='Nombre de vaisseaux: 1666 Chasseur léger 1666'></a> hostile de playerNick <a href='writemessages.php?session=111111&messageziel=22222222'><img src='http://80.237.203.201/download/use/asgard/img/m.gif' title='Ecrire un message' alt='Ecrire un message'></a> venant de la planète planetName [5:87:4] atteint la planète planetName [2:10:7]. Elle avait pour mission: Attaquer</span>

// Anglais (Attaque):
// <span class='flight attack'>A hostile <a href='#' onmouseover='this.T_WIDTH=150;return escape("Number of ships 4 &lt;br&gt;")' class='attack'>fleet</a><a href='' title='Number of ships 4 '></a> from playerName <a href='writemessages.php?session=1111111&messageziel=0000000'><img src='http://00000000.de/epicblue/img/m.gif' title='write message' alt='write message'></a> from planet planetName [5:4:8] is approaching planet planetName [5:139:9]. Its mission is: Attack.

// Espagnol (espionnage):
// <span class="flight espionage">Una <a href="#" onmouseover='this.T_WIDTH=150;return escape("Número de naves: 2 <br>Nave grande de carga <br>Sonda de espionaje <br>")' class="espionage">flota</a><a href="" title="Número de naves: 2 Nave grande de carga Sonda de espionaje "></a> enemiga de playerNick <a href="http://00000.de/game/writemessages.php?session=0000000&amp;messageziel=11111111"><img src="overview_data/m.gif" title="Escribir mensaje" alt="Escribir mensaje"></a> de el planeta planetName [7:4:6] llega a el planeta planetName [1:5:10]. La misión es: Espionaje</span>
// Espagnol (attaque):
// <span class="flight attack">Una <a href="#" onmouseover='this.T_WIDTH=150;return escape("Número de naves: 8 <br>Nave grande de carga <br>Cazador ligero <br>Sonda de espionaje <br>")' class="attack">flota</a><a href="" title="Número de naves: 8 Nave grande de carga Cazador ligero Sonda de espionaje "></a> enemiga de playerNick <a href="http://1111.de/game/writemessages.php?session=4444&amp;messageziel=00000"><img src="overview_data/m.gif" title="Escribir mensaje" alt="Escribir mensaje"></a> de el planeta planetName [7:7:6] llega a el planeta planetName [1:5:10]. La misión es: Atacar


          if bChecked then begin
             // La flotte gueriere est toujours vu dans le sens "aller"
             FAppFlotteMsg.Direction  := odAller;

             FAppFlotteMsg.bOwnFlotte := false;
             FAppFlotteMsg.bColorMenace := true;

             FTypeMsg := CNT_FLOTTE_TYPEMSG_ENNEMI_ALLER;
             exit;
          end;








          /////////////////////////////////////////////////////
          // ENNEMI FLOTTE PACIFIQUE - DEBUT
          /////////////////////////////////////////////////////
          bChecked := false;

          if SameText(FSpanClass, APERCU_SPAN_CLASS_ENNEMI_TRANSPORT_PACIFIQUE) then begin
             // verifie par la class d'affichage de couleur
             bChecked := true;
             FAppFlotteMsg.Ordre := ooTransport;
             
          end else if FUseSpanClass_AND_MsgGame_If_Fail or (FSpanClass = '')  then begin

             if pos(LangParsing.GetData('apercu_poslw_pacifique_flotte', 'une pacifique flotte'), ContentTrimLw) > 0 then begin
                bChecked := true;
                FAppFlotteMsg.Ordre := ooNeant;
             end;

          end;

// Français:
// <span class='flight transport'>Une <a href='#' onmouseover='this.T_WIDTH=150;return escape("Nombre de vaisseaux: 1 &lt;br&gt;Chasseur léger &lt;br&gt;")' class='transport'>flotte</a><a href='' title='Nombre de vaisseaux: 1 Chasseur léger '></a> pacifique de XXXXXXX <a href='writemessages.php?session=111111&messageziel=0000000'><img src='http://127.0.0.1:7774/ogame/skinx/img/m.gif' title='Ecrire un message' alt='Ecrire un message'></a> venant de la planète planetName [4:4:4] atteint la planète planetName [4:45:1]. Elle avait pour mission: Transporter</span>
// Espangol:
// <span class="flight transport">Una <a href="#" onmouseover='this.T_WIDTH=150;return escape("Número de naves: 1 <br>Nave grande de carga <br>")' class="transport">flota</a><a href="" title="Número de naves: 1 Nave grande de carga "></a> pacífica de XXXXXXX <a href="http://ppppppp/game/writemessages.php?session=000000&amp;messageziel=1111"><img src="overview_data/m.gif" title="Escribir mensaje" alt="Escribir mensaje"></a> de el planeta planetName [1:47:6] llega a el planeta planetName [1:12:10]. La misión es: Transportar</span>
// Anglais:
// <span class='flight transport'>A friendly <a href='#' onmouseover='this.T_WIDTH=150;return escape("")' class='transport'>fleet</a><a href='' title=''></a> from XXXXXXX <a href='writemessages.php?session=1111&messageziel=0000000'><img src='http://yyyyyyy/epicblue/img/m.gif' title='write message' alt='write message'></a> from planet planetName [7:4:12] is approaching planet planetName [5:4:9]. Its mission is: Transport.</span>


          if bChecked then begin
             // La flotte alliées est toujours vu dans le sens "aller"
             FAppFlotteMsg.Direction    := odAller;
             FAppFlotteMsg.bOwnFlotte   := false;
             FAppFlotteMsg.bColorMenace := false;

             FTypeMsg := CNT_FLOTTE_TYPEMSG_TRANSPORTALLIE_ALLER;

             exit;
          end;


          // Sinon, erreur...




          
       end else begin
          // C'est un message suivant
          // Sauvegarde le texte
          FAppFlotteMsg.Msg := FAppFlotteMsg.Msg + ' ' + Content;


          case FTypeMsg of



          /////////////////////////////////////////////////////
          // PROPRE FLOTTE - SUITE
          /////////////////////////////////////////////////////
              CNT_FLOTTE_TYPEMSG_TRANSPORTPLANETE_ALLER: begin



                         if FContentPos = 2 then begin
                            // Content ne contient que le mot "flottes"
                            // Il y a rien à faire
                            // On rajoute dans FAppFlotteMsg.Msg le contenu de title de la balise A.

                            if FTitleBaliseA <> '' then begin
                               FAppFlotteMsg.Msg := FAppFlotteMsg.Msg + ' (' + FTitleBaliseA + ')';

                               FAppFlotteMsg.VaisseauxStr := FTitleBaliseA;

                               // Calcul le nombre de vaisseaux ici
                               FAppFlotteMsg.NbVaisseau := mamCalculNbVaisseauxOwnFlotteV73c(FTitleBaliseA);
                               // Grand transporteur 12; Croiseur 15; Vaisseau de bataille 40

                            end;


                         end else if FContentPos = 3 then begin
                            FFlotteBuffer := Content;

                         end else if (FContentPos = 4) or
                                     (FContentPos = 5) then begin

                            // 4: coord
                            // 5: suite

                            FFlotteBuffer := FFlotteBuffer + ' ' + Content;

                         end else if FContentPos = 6 then begin
                            // 6: coord

                            FFlotteBuffer := FFlotteBuffer + ' ' + Content;

                            GestionMsgFlotteLaNotre(FFlotteBuffer);

                            FFlotteBuffer := '';

                            // 7: Mission start
                            // 8: mission

                         end else if FContentPos = 8 then begin
                            // Normalement il ne reste plus que l'ordre, qui devrait être "Transport"
                            // <a href="#" title="Deutérium: 60.001">Transport
                            // <br />

                            if FTitleBaliseA <> '' then begin
                               FTitleBaliseA := sfcRemplace(FTitleBaliseA, '<br />', '; ');
                               FTitleBaliseA := sfcRemplace(FTitleBaliseA, '<br >', '; ');
                               FTitleBaliseA := sfcRemplace(FTitleBaliseA, '<br>', '; ');
                               FTitleBaliseA := sfcRemplace(FTitleBaliseA, ': ;', ': ');
                               FTitleBaliseA := sfcRemplace(FTitleBaliseA, ':;', ':');

                               FTitleBaliseA := sfcRemplace(FTitleBaliseA, '   ', ' ');
                               FTitleBaliseA := sfcRemplace(FTitleBaliseA, '  ', ' ');
                               FTitleBaliseA := sfcRemplace(FTitleBaliseA, '")', '');

                               FAppFlotteMsg.Msg := FAppFlotteMsg.Msg + ' (' + FTitleBaliseA + ')';

                            end;


                            if (FAppFlotteMsg.Ordre = ooNeant) or FOverrideSpanClassOrdre then begin
                               // l'ordre n'a pas été trouvé avec le SPAN CLASS
                               FAppFlotteMsg.Ordre := mamOrdreStrToType(Content);
                            end;

                            
                         end;


                     end;



          /////////////////////////////////////////////////////
          // ENNEMI FLOTTE HOSTILE - SUITE
          // Attaque ou sondage
          /////////////////////////////////////////////////////

              CNT_FLOTTE_TYPEMSG_ENNEMI_ALLER: begin


                         if FContentPos = 2 then begin
                            // contient seulement le mot "flotte"
                            FAppFlotteMsg.VaisseauxStr := GetVaisseauxStrFromJS(FTitleBaliseA, FAppFlotteMsg.NbVaisseau );


                            
                         end else if FContentPos = 3 then begin
                            // Exemple: "hostile de xxx"

                            // Contient le pseudo de l'attaquant
                            // le pseudo peut contenir des espaces
                            // A ADAPTE en fonction des langues:
                            FAppFlotteMsg.PlayerFlotte := sfcTokenGet(Content, -3, ' ');



                         end else if FContentPos = 4 then begin
                            // Contient les coordonnées de départ/arrivée
                            FFlotteBuffer := Content;

                         end else if (FContentPos = 5) or
                                     (FContentPos = 6)  then begin
                            // 5: coord
                            // 6: suite
                            FFlotteBuffer := FFlotteBuffer + ' ' + Content;


                         end else if FContentPos = 7 then begin
                            // 7: coord
                            FFlotteBuffer := FFlotteBuffer + ' ' + Content;

                            GestionMsgFlotteAutreJoueur(FFlotteBuffer);

                         end;

                     end;




          /////////////////////////////////////////////////////
          // ENNEMI FLOTTE PACIFIQUE - DEBUT
          /////////////////////////////////////////////////////
              CNT_FLOTTE_TYPEMSG_TRANSPORTALLIE_ALLER: begin
                         if FContentPos = 2 then begin
                            // contient seulement le mot "flotte"
                            FAppFlotteMsg.VaisseauxStr := GetVaisseauxStrFromJS(FTitleBaliseA, FAppFlotteMsg.NbVaisseau );


                            
                         end else if FContentPos = 3 then begin
                            // Exemple: "pacifique de xxx"

                            // Contient le pseudo de l'attaquant
                            // le pseudo peut contenir des espaces
                            // A ADAPTE en fonction des langues
                            // NE PAS COMETTRE L'ERREUR de fusionner le code
                            // avec CNT_FLOTTE_TYPEMSG_ENNEMI_ALLER car il est
                            // similaire, mais il se peut qu'il ne le soit pas
                            // avec d'autre langage
                            FAppFlotteMsg.PlayerFlotte := sfcTokenGet(Content, -3, ' ');



                         end else if FContentPos = 4 then begin
                            // Contient les coordonnées de départ/arrivée
                            GestionMsgFlotteAutreJoueur(Content);

                         end;

                     end;

          end;


       end;

             // Une guerrière flotte  de joueur playerNick de la planète planetName [1:10:8]
	          // <a href="writemessages.php?session=1111111&messageziel=00000000">
	          // <img src="http://80.237.203.201/download/use/asgard/img/m.gif" border=0 alt="Ecrire un message"></a>
	          // se rapproche de la planète planetName[1:7:5] Cette flotte est composée de 184 Vaisseauxs. ( 4*Grand transporteur, 180*Vaisseau de bataille) Son ordre est: Attaquer



       // Retour (tout en un message)
       // Une de tes  flottes de la planète planetName 1:4:5 revient de la planète planetName [1:4:6] à sa planète de départ.Sa mission est: Transport


       // Transport allié
       // Une pacifique flotte  de joueur playerNick de la planète planetName [7:1:5]
       // <a href="writemessages.php?session=0000000&messageziel=111111111">
       // <img src="http://80.237.203.201/download/use/asgard/img/m.gif" border=0 alt="Ecrire un message"></a>
       // se rapproche de la planète planetName[1:4:6] Cette flotte est composée de 5 Vaisseauxs. ( 5*Grand transporteur) Son ordre est: Transport


       exit;
    end;

    if FWhatIsNextContent <> CNT_NEXT_CONTENT_UNKNOW then begin

       // Réinitialise la valeur
       xPos := FWhatIsNextContent;
       FWhatIsNextContent := CNT_NEXT_CONTENT_UNKNOW;

       case xPos of
           CNT_NEXT_CONTENT_PLANETNAME: begin
                             // Planète      &quot;PlaneteNom&quot;
                             xPos := pos('&quot;', lowercase(Content));
                             lngPos := 5;

                             if (xPos < 1) then begin
                                xPos := pos('"', lowercase(Content));
                                lngPos := 0;
                             end;


                             if xPos > 0 then begin
                                System.Delete(Content, 1, xPos + lngPos);

                                xPos := pos('&quot;', lowercase(Content));
                                if (xPos < 1) then begin
                                   xPos := pos('"', lowercase(Content));
                                end;

                                if xPos > 0 then begin
                                   System.Delete(Content, xPos, maxint);

                                   FCurrNomPlantet := Content;
                                   FWhatIsNextContent := CNT_NEXT_CONTENT_PSEUDOJOUEUR;

                                end;
                             end;
                             
                         end;

           CNT_NEXT_CONTENT_PSEUDOJOUEUR: begin
                                //  (NickPlayer)
                                xPos := pos('(', Content);
                                if xPos > 0 then begin
                                   System.Delete(Content, 1, xPos);
                                   xPos := pos(')', Content);

                                   if xPos > 0 then begin
                                      System.Delete(Content, xPos, maxint);

                                      FCurrNomJoueur := Content;

                                   end;
                                end;

                         end;

           CNT_NEXT_CONTENT_NEWMESSAGE: begin
                             // Tu as 2 nouveau(x) message(s)s
                             exit;

                         end;

           CNT_NEXT_CONTENT_POINTS: begin
                             // 1045 (Place 4222 de 10915)
                             Content := sfcRemplace(trim(Content), '.', '');
                             ExtractPointClassement(Content);

                             FWhatIsNextContent := CNT_NEXT_CONTENT_POINTS_PLACE;

                         end;

           CNT_NEXT_CONTENT_POINTS_PLACE: begin
                             // Nouveau format de points:
                             // 95248 (Place <a href='stat.php?session=000000&start=401'>409</a> de 9249)
                             // ici, on ne contient que la place
                             Content := sfcRemplace(trim(Content), '.', '');
                             FClassementPosition := StrToIntDef(Content, -1);

                             FWhatIsNextContent := CNT_NEXT_CONTENT_POINTS_NBPLAYERS;

                         end;

           CNT_NEXT_CONTENT_POINTS_NBPLAYERS: begin
                             // de 9249)
                             Content := trim(Content);
                             Content := sfcRemplace(Content, '.', '');

                             xPos := pos(')', Content);
                             if xPos > 0 then
                                System.Delete(Content, xPos, maxint);

                             xPos := pos(' ', Content);
                             if xPos > 0 then
                                System.Delete(Content, 1, xPos);

                             FClassementTotalPlayers :=  StrToIntDef(Content, -1);

                         end;

           CNT_NEXT_CONTENT_IN_DIAMETRE, CNT_NEXT_CONTENT_IN_DIAMETRE_BUF: begin
                             // Remet le flag, le tampon est traité au début de
                             // la prochaine ligne
                             FWhatIsNextContent := CNT_NEXT_CONTENT_IN_DIAMETRE_BUF;

                             // Ne pas oublier que le parseur supprimer les
                             // espaces de droite et de gauche tout seul
                             FTamponTraitement := FTamponTraitement + Content;
                         end;


           CNT_NEXT_CONTENT_SERVER_TIME: begin
                             // Wed Nov 23 20:55:08
                             FDateServeur := OGDATETIME_StrToUnix(Content);

                             if FDateServeur < 0 then
                                FDateServeur := 0;
                                
                         end;


       end;

       exit;
    end;

    // Les majuscules n'ont plus d'intéret dans la suite
    Content := sfcSupprAccentsAll(lowercase(trim(Content)));



    if SameText(Content, LangParsing.GetData('vuegen_stsa_points', 'points')) then begin
       FWhatIsNextContent := CNT_NEXT_CONTENT_POINTS;

    end else if SameText(Content, LangParsing.GetData('vuegen_stsa_diametre', 'diametre')) then begin
       FWhatIsNextContent := CNT_NEXT_CONTENT_IN_DIAMETRE;

    end else if pos(LangParsing.GetData('apercu_lwpos_heure_serveur', 'heure du serveur'), Content) > 0 then begin
       FWhatIsNextContent := CNT_NEXT_CONTENT_SERVER_TIME;

    end;







end;


////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////



constructor TParsingDebutDocumentMineraiAndPlanet.Create(Scanneur: TEasyXmlScanner);
begin
    inherited Create;

    FScanneur := Scanneur;
    FOtherPlanetLink := TCollectionLinkOtherPlanete.Create;


end;

destructor TParsingDebutDocumentMineraiAndPlanet.Destroy;
begin
    FOtherPlanetLink.Free;

    inherited Destroy;
end;


procedure TParsingDebutDocumentMineraiAndPlanet.TraitementTamponEnergie;
var xPos: integer;
begin
    if FTamponDejaTraite then exit;

    // -20/1.786
    xPos := pos('/', FTamponForEnergie);

    if xPos = 0 then
       FCurrentRessource.Energie := 0
    else begin
       FTamponForEnergie := copy(FTamponForEnergie, 1, xPos - 1);
       FCurrentRessource.Energie := StrToIntDef(FTamponForEnergie, 0);
    end;

    FTamponDejaTraite := true;



end;

function TParsingDebutDocumentMineraiAndPlanet.IsValidPage: boolean;
begin
   Result := False;

   if NoT(FExistHTML) then
      exit;

   if NoT(FExistBODY) then
      exit;

   Result := true;

end;

function TParsingDebutDocumentMineraiAndPlanet.IsValidHeader: boolean;
begin
   Result := IsValidPage;

   if NoT(Result) then
      exit;

   if FCurrentPlanete.Galaxie < 0  then begin
      exit;
   end;

   Result := true;

end;

procedure TParsingDebutDocumentMineraiAndPlanet.Prepare;
begin
    FCurrentRessource.Metal := -1;
    FCurrentRessource.Cristal := -1;
    FCurrentRessource.Deuterium := -1;
    FCurrentRessource.Energie := 0;

    FCurrentPlanete.Galaxie       := -1;
    FCurrentPlanete.SystemSolaire := -1;
    FCurrentPlanete.Position      := -1;

    FInSelect := false;
    FInOption := 0;
    FCheckCondition := 0;
    FWitchLigneIsGood := -1;
    FTamponForEnergie := '';
    FTamponDejaTraite := false;


    // Modifie les fonctions
    FScanneur.OnEndTag   := ScanOnEndTag;
    FScanneur.OnEmptyTag := nil;
    FScanneur.OnStartTag := ScanOnStartTag;
    FScanneur.OnContent  := ScanOnContent;

    FError := false;

    FLastLinkPlaneteInfo.Location.Galaxie := -1;
    FLastLinkPlaneteInfo.Location.SystemSolaire := -1;
    FLastLinkPlaneteInfo.Location.Position  := -1;
    FLastLinkPlaneteInfo.Lien := '';

    // Efface les autres planètes
    FOtherPlanetLink.Clear;

       FExistHTML := false;
       FExistBODY := false;

    FExistCommandant := false;
    FExistOfficier   := false;
    FCheckingOfficierDone := false;
    
end;


function TParsingDebutDocumentMineraiAndPlanet.GetPlaneteStr: string;
begin
    Result := mbtPlanetLocationToStr(FCurrentPlanete);
end;


procedure TParsingDebutDocumentMineraiAndPlanet.ScanOnStartTag(Sender: TObject; TagName: string; Attributes: TAttrList);
var CurrBalise: string;
    xPos : integer;
begin
   TagName := lowercase(TagName);

   if TagName = 'select' then begin
      // Ceci permet de choisir la planète que l'on veut gérer
      // <select  size=1 onchange="haha(this)">
      // <option  value="/game/buildings.php?session=sessionid&cp=11111111&mode=Verteidigung&gid=&messageziel=&re=0" selected>PlaneteNom [1:2:3]</select>
      FInSelect := true;

   end else if TagName = 'option' then begin

      if FInSelect then begin
          CurrBalise := trim(Attributes.Value('selected'));
          FTamponForOption := '';

          if CurrBalise = '1' then
             FInOption := 2
          else begin
             // Sauvegarde le lien
             FInOption := 1;

             FLastLinkPlaneteInfo.Lien := Attributes.Value('value');

          end;

      end;

   end else if TagName = 'table' then begin
      FCurrLigne := 0;
      FCurrColonne := 0;
   end else if TagName = 'tr' then begin
      Inc(FCurrLigne);
      FCurrColonne := 0;

   end else if (TagName = 'td') or (TagName = 'th') then begin
      Inc(FCurrColonne);


   end else if TagName = 'html' then begin
      FExistHTML := true;

   end else if TagName = 'body' then begin
      FExistBODY := true;

   end else if TagName = 'img' then begin
      // detection compte commandant et officiel
      // FExistOfficier
      CurrBalise := trim(Attributes.Value('src'));

      xPos := LastDelimiter('/', CurrBalise);
      if xPos > 0 then begin
         System.Delete(CurrBalise, 1, xPos);

         if SameText(CurrBalise, '') then begin
            // sans: http://uuuuu/game/img/commander_ikon_un.gif
            // avec: http://iiiii/game/img/commander_ikon.gif
            // Deduction: "un" signifie "sans"
            FExistCommandant := true;

         end else if SameText(CurrBalise, 'admiral_ikon.gif') then begin
            // sans: admiral_ikon_un.gif
            FExistOfficier := true;

         end else if SameText(CurrBalise, 'ingenieur_ikon.gif') then begin
            // sans: ingenieur_ikon_un.gif
            FExistOfficier := true;

         end else if SameText(CurrBalise, 'geologe_ikon.gif') then begin
            // sans: geologe_ikon_un.gif
            FExistOfficier := true;


         end else if SameText(CurrBalise, 'technokrat_ikon.gif') then begin
            // sans: technokrat_ikon_un.gif
            FExistOfficier := true;

         end;

         CurrBalise := lowercase(CurrBalise);

         if pos('_ikon', CurrBalise) > 0 then begin
            FCheckingOfficierDone := true;
         end;

         {$IFDEF OFFICIER_OK}
             //FExistOfficier := false;
         {$ENDIF}



      end;

   end;


end;

procedure TParsingDebutDocumentMineraiAndPlanet.ScanOnEndTag(Sender: TObject; TagName: string);
begin
   TagName := lowercase(TagName);

   if TagName = 'select' then begin
      FInSelect := false;
      FInOption := 0;

   end else if TagName = 'option' then begin
      // Note: la balise de fin d'option n'existe pas

      if FInSelect then begin
         FTamponForOption := trim(FTamponForOption);
         OnOptionData(FTamponForOption);
         FTamponForOption := '';
      end;


      FInOption := 0;

   end else if TagName = 'table' then begin
      if (FWitchLigneIsGood > 0) and (FCheckingOfficierDone) then begin
          TraitementTamponEnergie;

          // Indique que l'on a finit le traitement
          if Assigned(FOnFinTravail) then
             FOnFinTravail(Self);
      end;

         
   end;

end;

procedure TParsingDebutDocumentMineraiAndPlanet.DoDebugMinerai(const Msg: string);
begin
    {$IFDEF DEBUG}
       if Assigned(FDebugProc) then begin
          FDebugProc('Header -> ' + Msg);
       end;
    {$ENDIF}
end;

procedure TParsingDebutDocumentMineraiAndPlanet.OnOptionData(Content: string);
label lDoCheck;
var xPos: integer;
    MoonCertain: boolean;
    MoonPosition: integer;

    peItem: PLinkOtherPlanete;

begin

    Content := trim(Content);

    //DoDebugMinerai(Content);
    

    MoonPosition := pos(lowercase(LangParsing.GetData('header_planetlist_LuneLwPos', 'lune')), lowercase(Content));
    MoonCertain  := false;

    if MoonPosition > 0 then begin
       if pos('(', Content) > 0 then begin
          // c'est une lune
          // car avec la nouvelle version, les lunes peuvent se situées avant les planètes...
          // MAIS uniquement lorsqu'elles sont renommées
          MoonCertain := true;
       end;
    end;


    if FInOption = 2 then begin
       // <option  value="/game/buildings.php?session=11111111111&cp=00000000&mode=Verteidigung&gid=&messageziel=&re=0" selected>
       // PlaneteNom [1:2:3]</select>


       xPos := LastDelimiter(' ', Content);
       if xPos > 0 then begin
           FCurrentPlaneteNom := copy(Content, 1, xPos - 1);
           
           System.Delete(Content, 1, xPos);
           FCurrentPlanete := mpcExtractPlanetLocation(Content);

           if MoonCertain then begin
              FCurrentPlanete.Position := FCurrentPlanete.Position + CNT_POSITION_LUNE;
           end;

           peItem := FOtherPlanetLink.Get_Pointeur(FCurrentPlanete);

           if peItem <> nil then begin
              // la planète est sélectionnée, elle n'est donc pas censée déjà exister
              // dans la liste des planètes
              // SAUF avant lors de la gestion des lunes, mais à présent, elles sont
              // bien gérées...
              // si on arrive ici, c'est qu'il y a forcément une erreur quelque part
              // edit: en fait non, j'avais oublié le cas de lune non renommée qui ne
              // possède pas le caractère "("


              if MoonCertain then begin
                 // bizarre
                 DoDebugMinerai('Attention: la planète sélectionnée existe déjà dans la liste (Identifiée comme lune) - ' + Content);

                    // rectifie celui de l'items
                    if peItem.Location.Position >= CNT_POSITION_LUNE then begin
                       // il a bien le rang de lune
                       // rectifie son rang
                       DoDebugMinerai('Rectification...');
                       peItem.Location.Position := peItem.Location.Position - CNT_POSITION_LUNE;

                    end else begin
                       // sinon erreur...
                       DoDebugMinerai('Erreur: Bizarre 11 - ' + Content);

                    end;



              end else if MoonPosition < 1 then begin
                 // ce n'est pas une lune, ni une lune renommé
                 // donc on ne devrait pas arriver ici
                 // SAUF si la lune est avant et qu'elle
                 // a été identifié en tant que planète (donc une lune non renommée située avant)
                 DoDebugMinerai('Attention: la planète sélectionnée existe déjà dans la liste - ' + Content);


                    // l'élément actuel est bel et bien une planète, c'est l'élément précédent
                    // qui ne l'était pas
                    // on rectifie le tir:
                    if peItem.Location.Position < CNT_POSITION_LUNE then begin
                       // il a bien le rang de planète
                       DoDebugMinerai('Rectification...');
                       peItem.Location.Position := peItem.Location.Position + CNT_POSITION_LUNE;

                    end else begin
                       // a ne rien comprendre...
                       // c'est impossible d'arriver ici
                       DoDebugMinerai('Erreur: Bizarre 12 - ' + Content);

                    end;


              end else begin
                 // sinon MoonPosition >= 1
                 // c'est une lune non renommée dont la planète a déjà été identifié
                 FCurrentPlanete.Position := FCurrentPlanete.Position + CNT_POSITION_LUNE;

                 if (FOtherPlanetLink.Get_Index(FCurrentPlanete)) >= 0 then begin
                     DoDebugMinerai('Erreur: la planète sélectionnée existe déjà dans la liste (et la lune, et la planète) - ' + Content);
                 end;
              end;

           end;


       end else begin
          DoDebugMinerai('Erreur: Espace non trouvé (2) - ' + Content);
       end;


       exit;


    end else if FInOption = 1 then begin
       // TODO: Sauvegarder les autres planéte, pour connaitre le lien pour
       // y accéder
       // <option  value="/game/resources.php?session=1111111&cp=00000000&mode=&gid=&messageziel=&re=0" >
       // planetName [4:7:15]</select>

       xPos := LastDelimiter(' ', Content);
       if xPos > 0 then begin
           FLastLinkPlaneteInfo.Nom := copy(Content, 1, xPos - 1);
           System.Delete(Content, 1, xPos);
           FLastLinkPlaneteInfo.Location := mpcExtractPlanetLocation(Content);

           if MoonCertain then begin
              FLastLinkPlaneteInfo.Location.Position := FLastLinkPlaneteInfo.Location.Position + CNT_POSITION_LUNE;
           end;


           // Vérifie si le lien est valide (sinon c'est inutile d'ajouter la planète)
           if FLastLinkPlaneteInfo.Lien <> '' then begin

              peItem := FOtherPlanetLink.Get_Pointeur(FLastLinkPlaneteInfo.Location);

              if peItem <> nil then begin
                 // c'est probablement une lune car la location existe déjà
                 // MAIS, ce le problème des lunes est mieux géré
                 // si la planète existe déjà, c'est une erreur
                 //DoDebugMinerai('Erreur: La planète existe déjà - ' + Content);
                 //exit;


lDoCheck:
                 if MoonCertain then begin
                    // bizarre...
                    // sauf si la planète a été identifié comme lune (avec le nom "Lune")
                    // mais ce cas est improbable puisqu'on ajoute en tant que planète
                    // lorsque c'est le cas
                    DoDebugMinerai('Attention: la planète existe déjà dans la liste (Identifiée comme lune) - ' + Content);

                    // rectifie celui de l'items
                    if peItem.Location.Position >= CNT_POSITION_LUNE then begin
                       // il a bien le rang de lune
                       // rectifie son rang
                       DoDebugMinerai('Rectification...');
                       peItem.Location.Position := peItem.Location.Position - CNT_POSITION_LUNE;

                    end else begin
                       // sinon erreur...
                       DoDebugMinerai('Erreur: Bizarre 01 - ' + Content);

                    end;



                 end else if MoonPosition < 1 then begin
                    // ce n'est pas une lune, ni une lune renommée
                    // donc on ne devrait pas arriver ici,
                    // SAUF si la lune est avant et qu'elle
                    // a été identifié en tant que planète (donc une lune non renommée située avant)
                    DoDebugMinerai('Attention: la planète existe déjà dans la liste - ' + Content);

                    // l'élément actuel est bel et bien une planète, c'est l'élément précédent
                    // qui ne l'était pas
                    // on rectifie le tir:
                    if peItem.Location.Position < CNT_POSITION_LUNE then begin
                       // il a bien le rang de planète
                       DoDebugMinerai('Rectification...');
                       peItem.Location.Position := peItem.Location.Position + CNT_POSITION_LUNE;

                    end else begin
                       // a ne rien comprendre...
                       // c'est impossible d'arriver ici
                       DoDebugMinerai('Erreur: Bizarre 02 - ' + Content);

                    end;



                 end else begin
                    // sinon MoonPosition >= 1
                    // c'est une lune non renommée dont la planète a déjà été identifié
                    FLastLinkPlaneteInfo.Location.Position := FLastLinkPlaneteInfo.Location.Position + CNT_POSITION_LUNE;

                    if (FOtherPlanetLink.Get_Index(FLastLinkPlaneteInfo.Location)) >= 0 then begin
                       DoDebugMinerai('Erreur: la planète existe déjà dans la liste (et la lune, et la planète) - ' + Content);
                    end;

                 end;



              end else if CompareLocation(FCurrentPlanete, FLastLinkPlaneteInfo.Location) then begin
                 // c'est probablement une lune (cas où la planète de la lune est la planète courante)
                 // MAIS, encore une fois, le problème des lunes a été mieux géré
                 // normalement on n'arrive jamais ici
                 //DoDebugMinerai('Erreur: La planète possède les mêmes coordonnées que la planète courante - ' + Content);
                 //exit;

                 goto lDoCheck;

                 
                 (*
                 if MoonPossible then begin
                    FLastLinkPlaneteInfo.Location.Position := FLastLinkPlaneteInfo.Location.Position + CNT_POSITION_LUNE;

                 end else begin

                 end;
                 *)


              end;



              FOtherPlanetLink.Add(FLastLinkPlaneteInfo);

              FLastLinkPlaneteInfo.Lien := '';
           end;

       end else begin
          DoDebugMinerai('Erreur: Espace non trouvé (1) - ' + Content);
       end;


    end;


end;

procedure TParsingDebutDocumentMineraiAndPlanet.ScanOnContent(Sender: TObject; Content: string);
var xPos: integer;

begin

    if FInSelect then begin
       FTamponForOption := FTamponForOption + ' ' + Content;
       exit;
    end;

    Content := lowercase(trim(Content));

    //LangParsing.GetData('renergie', 'energie')


    if SameText(Content, LangParsing.GetData('header_st_metal', 'métal')) then begin
        Inc(FCheckCondition);
        FWitchLigneIsGood := FCurrLigne + 1;
        FWitchColonneIsGood := FCurrColonne;

    end else if SameText(Content, LangParsing.GetData('header_st_cristal', 'cristal')) then begin
        Inc(FCheckCondition);

    end else if SameText(Content, LangParsing.GetData('header_st_deuterium', 'deutérium')) then begin

        Inc(FCheckCondition);
    end;


    if FCurrLigne = FWitchLigneIsGood then begin
       case FCurrColonne of
            2: FCurrentRessource.Metal     := StrToIntDef(sfcRemplace(Content, '.', ''), -1);
            3: FCurrentRessource.Cristal   := StrToIntDef(sfcRemplace(Content, '.', ''), -1);
            4: FCurrentRessource.Deuterium := StrToIntDef(sfcRemplace(Content, '.', ''), -1);
            5: begin
                  FTamponForEnergie := FTamponForEnergie + Content;
               end;
            6: TraitementTamponEnergie;

       end;

    end;



end;


////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////


procedure TParsingBatiment.InitPointeur;
begin
    FCurrElement.GID             := -1;
    FCurrElement.Prix.Metal      :=  0;
    FCurrElement.Prix.Cristal    :=  0;
    FCurrElement.Prix.Deuterium  :=  0;
    FCurrElement.Prix.Energie    :=  0;

    
    FCurrElement.Duree           :=  0;
    FCurrElement.CanBeBuildIn    := -1;
    FCurrElement.CanBeBuildInOpt := -1;

    FCurrElement.Link            := '';
    FCurrElement.Nom             := '';
    FCurrElement.Niveau          := 0;
    FCurrElement.EnConstruction  := false;

    
    FCurrElement.LigneInGrid  := -1;
    FCurrElement.GIDType       := tgidAutre;
    FCurrElement.ConstructionFinDans := -1;

end;

procedure TParsingBatiment.ScanOnStartTag(Sender: TObject; TagName: string; Attributes: TAttrList);
var CurrBalise: string;
    xPos : integer;
begin
   TagName := lowercase(TagName);


   if TagName = 'form' then begin
      FInForm := true;

      FFormAction := Attributes.Value('action');

   end else if TagName = 'table' then begin
      FInTable := true;

      FCurrTableLigne  := 0;
      FCurrTableColonne := 0;


   end;

   if FFormMode and (FInForm = false) then exit;
   if NoT(FInTable) then exit;

   if TagName = 'tr' then begin
      // Nouvelle ligne
      FCurrTableColonne := 0;
      Inc(FCurrTableLigne);

      if FCurrElement <> nil then begin
         // On le sauvegarde
         if FCurrElement.Gid > 0 then begin
            FCurrElement.GIDType       := GetTypeOfTGID(FCurrElement.GID);
            FElementsList.Add(FCurrElement);

         end else
            // Pointeur invalide
            Dispose(FCurrElement);

         FCurrElement := nil;
      end;

   end else if (TagName = 'td') or (TagName = 'th') then begin
      Inc(FCurrTableColonne);

   end else if TagName = 'a' then begin
      FInLink := true;

      if FCurrTableColonne = 2 then begin
          // Lien pour avoir des informations sur l'élément
          // Ce lien est utile car il permet d'extraire le GID de l'élément
          // <a href=infos.php?session=0000000&gid=202>
          // Et il va aussi permettre d'extraire le nom de l'élément


          CurrBalise := Attributes.Value('href');
          CurrBalise := lowercase(CurrBalise);

          xPos := pos('&gid=', CurrBalise);
          if xPos > 0 then begin
              FInLinkInfoElementStr := true;

              System.Delete(CurrBalise, 1, xPos + 4);

              // Au cas où d'autre paramètre sont après le gid
              xPos := pos('&', CurrBalise);
              if xPos > 0 then
                 System.Delete(CurrBalise, xPos, maxint);


              try
                 xPos := StrToIntDef(CurrBalise, -1);
              except
                 xPos := -2;
              end;

              if xPos < 0 then begin
                  // Echec de conversion
                  FError := true;

              end else begin
                  // Sinon c'est ici que l'élément se créer et prend forme
                  if FCurrElement <> nil then begin
                     // on le sauvegarde
                     //FRes.Add(FCurrElement);
                     //FCurrElement := nil;
                     // Il a du déjà être sauvegardé lors du changement de ligne
                     FError := true;
                  end;

                  // Créé un nouvel élément
                  New(FCurrElement);
                  InitPointeur;

                  FCurrElement.Gid := xPos;

              end;


          end;


      end else if FCurrTableColonne = 3 then begin
          // Lien de construction
          // <a href=b_building.php?session=111111111111&bau=21&cp=101010101>

          // si c'est avec le compte commandant
          // on a un lien pour annuler la construction
          // mais FCurrElement est à nil

          if FCurrElement = nil then begin

             if FElementsList.Count > 0 then begin
                // pour le premier élément, il se peut donc
                // que ce soit le compte commandant
                FError := true;
             end;

          end else
             FCurrElement.Link := Attributes.Value('href');


      end;

   end else if TagName = 'input' then begin

      if FCurrTableColonne = 3 then begin
          // Zone de saisie pour indiquer le nombre d'unité à construire
          // <input type=text name=fmenge[205] alt='Chasseur lourd' size=6 maxlength=6 value=0 tabindex=1>

          if FCurrElement = nil then
             FError := true
          else
             FCurrElement.Link := Attributes.Value('name');


      end;

   end else if TagName = 'br' then begin
      if FInRessourceNeed then begin
         // Traite le tampon FInLinkInfoElementStr
         // Métal:<b>3.000</b> Cristal:<b>1.000</b> Deutérium:<b>0</b> Énergie:<b>0</b><br>
         // Donc:
         // Métal:3.000 Cristal:1.000 Deutérium:0 Énergie:0

         FInRessourceNeed := false;

         if FCurrElement <> nil then begin
            FCurrElement.Prix := mpcExtractRessourceFromBuffer(FRessourceNeedStr);
         end;

      end;

   end else if TagName = 'script' then begin
      // pp="4411";pk="3";pl="1111111";ps="00000000";t();
      // A première vu, pp correspond au nombre de seconde restante avant
      // la fin de la construction

      // <a href=b_building.php?session="+ps+"&cp="+pl+">

      if FCurrTableColonne = 3 then begin
         // Cellule de construction
         if FCurrElement <> nil then begin

            FCurrElement.EnConstruction := true;
            FCannotBuild := true;

            FInScript := true;

            FNextMaybeScriptDurationConstruction := true;

            // FCurrElement.ConstructionFinDans
         end;

      end;


   end;

end;

procedure TParsingBatiment.ScanOnEndTag(Sender: TObject; TagName: string);
begin
   TagName := lowercase(TagName);

   if TagName = 'form' then begin
      FInForm := false;

   end else if TagName = 'table' then begin
      FInTable := false;

      if FCurrElement <> nil then begin
         FCurrElement.GIDType       := GetTypeOfTGID(FCurrElement.GID);
         FElementsList.Add(FCurrElement);
         FCurrElement := nil;
      end;

      FCurrTableLigne  := 0;
      FCurrTableColonne := 0;


   end else if TagName = 'script' then begin
      FInScript := false;

   end else if TagName = 'a' then begin
      FInLink := false;
      FInLinkInfoElementStr := false;

   end;

end;


procedure TParsingBatiment.ScanOnContent(Sender: TObject; Content: string);
label lblDispoChantier;
var xPos, i, lng, xPos2: integer;
    s, xPosStr: string;
begin

// Message lorsque l'on est en train de mettre à jour le centre de recherche:
// "Tu ne peux pas faire de recherche car le centre de recherche est en construction."
// Et les liens de recherche sont pourtant disponible, donc ce qu'il faut faire,
// c'est d'une part vérifie si la recherche a bien commencé après le lancement
// de l'une d'entre elles.



    if FCurrTableColonne = 3 then begin

        if FInScript then begin

          if FNextMaybeScriptDurationConstruction then begin
              // pp="159";pk="1";pl="1414141414";ps="000000000000";t();
              xPos := pos('pp', Content);

              if xPos = 0 then exit;
              System.Delete(Content, 1, xPos + 2);  // +2 pour enlever le =

              xPos := pos('"', Content);
              if xPos = 0 then exit;

              System.Delete(Content, 1, xPos);

              xPos := pos('"', Content);
              if xPos = 0 then exit;
              System.Delete(Content, xPos, maxint);

              try
                  if FCurrElement <> nil then
                     FCurrElement.ConstructionFinDans := StrToIntDef(Content, -1)
                  else
                     FError := true;

              except
                  FCurrElement.ConstructionFinDans := -1;
              end;

              FNextMaybeScriptDurationConstruction := false;

          end;

       end;

    end;



    // Le contenu utile n'est que celui de la colone 2
    if FCurrTableColonne <> 2 then exit;
    if NoT(FInTable) then exit;


    if FInLinkInfoElementStr then begin
        // <a href=infos.php?session=0000000000&gid=202>Petit transporteur</a>
        if FCurrElement = nil then
           FError := true
        else
           FCurrElement.Nom := Content;

        FInLinkInfoElementStr := false;
        FNextContentIsMaybeNiveau := true;

    end else if FNextContentIsMaybeNiveau then begin
        FNextContentIsMaybeNiveau := false;

        //  (Niveau 11 )
        Content := lowercase(Content);




        xPosStr := LangParsing.GetData('building_poslw_niveau', 'niveau');
        xpos := pos(xPosStr, Content);

        xPos2 := pos(LangParsing.GetData('chantierdef_poslw_disponible', 'disponible'), Content);


        if xPos > 0 then begin

           if (xPos2 > 0) then begin
               // pour le portugal, la chaine pour "niveau" est
               // incluse dans la chaine "disponible"
               if xPos2 < xPos then begin
                  goto lblDispoChantier;
               end;
           end;


           System.Delete(Content, 1, xPos + length(xPosStr));
           Content := trimleft(Content);

           lng := length(Content);
           if lng < 1 then exit;

           s := '';
           for i := 1 to lng do begin
              if Content[i] in sfc_ChiffresSet then begin
                 s := s + Content[i];
              end else
                 break;

           end;

           if s <> '' then begin
              xPos := StrToIntDef(s, -1);

              if xPos > 0 then begin
                 if FCurrElement = nil then
                    FError := true
                 else
                    FCurrElement.Niveau := xPos;

                 exit;
              end;

           end;

        end else begin
           //   ( 4 disponible(s) )
lblDispoChantier:
           xPos := pos(LangParsing.GetData('chantierdef_poslw_disponible', 'disponible'), Content);

           if xPos > 0 then begin
              Content := copy(Content, 1, xPos - 1);
              Content := trimright(Content);

              xPos := LastDelimiter(' ()', Content);
              if xPos > 0 then begin
                  System.Delete(Content, 1, xPos);

                  Content := sfcRemplace(Content, '.', '');
                  xPos := StrToIntDef(Content, -1);

                  if xPos < 0 then exit;

                  if FCurrElement = nil then
                     FError := true
                  else
                     FCurrElement.Niveau := xPos;
              end;

           end;


        end;




    end else if FInRessourceNeed then begin
        if Content <> '' then begin
          // Le parseur supprime tout seul les espaces super flu
          // On rajoute l'espace intelligement
          
          if NoT(Content[1] in sfc_ChiffresSet) then
             Content := ' ' + Content;

          FRessourceNeedStr := FRessourceNeedStr + Content;
        end;

    end else begin

        // Les majuscules sont inutile ici
        Content := lowercase(Content);


        // chantierdef_lw_duree_construct
        xPos := pos(LangParsing.GetData('items_lw_duree_construct', ' de construction :'), Content);
        if xPos > 0 then begin
           // <br>Durée de production:  19m 12s<br>
           // Durée de production: 8h 18m 47s
           // Durée de production: 1 Jour 1h 36m 00s
           // Durée de construction :  21m 20s<br>

           xPos := pos(':', Content);
           if xPos > 0 then begin
              System.Delete(Content, 1, xPos);
              Content := trimleft(content);

              if FCurrElement = nil then
                 FError := true
              else begin
                 FCurrElement.Duree := mpcExtractDureeFromStr(Content);
                 if FCurrElement.Duree < 0 then
                    FError := true;

              end;
           end;

           exit;
        end;



        xPos := pos(LangParsing.GetData('building_poslw_ressources_necessaire', 'essources nécessaires :'), lowercase(Content));
        if xPos > 0 then begin
           // <br>A besoin de: Métal:<b>3.000</b> Cristal:<b>1.000</b> Deutérium:<b>0</b> Énergie:<b>0</b><br>
           // Ressources nécessaires : Métal:
           xPos := pos(':', Content);
           System.Delete(Content, 1, xPos);
           FRessourceNeedStr := trimleft(content);
           FInRessourceNeed  := true;
        end;


    end;



end;


function TParsingBatiment.ParseBuffer(const Tampon: string): boolean;
begin

    Lock;

    inherited ParseBuffer(Tampon);

    FNextContentIsMaybeNiveau := false;
    FInLinkInfoElementStr := false;
    FInForm := false;
    FInTable := false;
    FInLink := false;
    FInRessourceNeed := false;
    FRessourceNeedStr := '';
    FInScript := false;

    FFormAction := '';
    FCannotBuild := false;

    //FInSelect := false;
    //FInOption := 0;

    FNextMaybeScriptDurationConstruction := false;


    FCurrElement := nil;

    if FDontFreeTList then begin
       // Efface juste la liste, car on ne veut pas les libérer (dont free)
       FElementsList.Clear;

    end else begin
       // Libére les pointeur et efface la liste
       FreePointeurAndClear;
    end;

    try
       FScanner.Execute;
    except
       FError := true;
    end;
(*
    if FError = false then begin
        if FCurrentRessource.Metal = -1 then
           FError := true;
        if FCurrentRessource.Cristal = -1 then
           FError := true;
        if FCurrentRessource.Deuterium = -1 then
           FError := true;

        if FCurrentPlanete.Galaxie = -1 then
           FError := true;
        if FCurrentPlanete.SystemSolaire = -1 then
           FError := true;
        if FCurrentPlanete.Position = -1 then
           FError := true;

    end;
*)

    Result := NoT(FError);

    if Result then begin
       Result := FHeaderParser.IsValidHeader;
    end;

    // on supprime toujours les pointeurs en les libérant
    // lors du prochain parsing (par défaut)
    // ceci sert lors du ChangePlanete où les pointeurs sont non utilisés
    FDontFreeTList := false;

    FNbElementTrouve := Valeurs.Count;

    Unlock;
    
end;

procedure TParsingBatiment.FreePointeurAndClear;
begin
    FElementsList.ClearAndDispose;
end;
constructor TParsingBatiment.Create(Scanner: TEasyXmlScanner);
begin
    inherited Create(Scanner);

    FElementsList  := TListElements.Create;

    // Ne libère PAS les pointeurs, ce n'est qu'un parseur, et on sous entend
    // que les pointeurs seront exploités et gérer à l'extérieur
    FDontFreeTList := true;



    FTypeClass := CLASSTYPE_ELEMENTS;
end;

destructor TParsingBatiment.Destroy;
begin

    if FDontFreeTList = false then
       FElementsList.ClearAndDispose;

    FElementsList.Free;

    inherited Destroy;
end;




////////////////////////////////////////////////////////////////////////////////
// Menu à gauche
////////////////////////////////////////////////////////////////////////////////

procedure TParsingMenuLeft.SaveToBackup;
var i: integer;
begin
    for i := CNT_MENU_ARRAY_ID_START to CNT_MENU_ARRAY_ID_END do begin
       FLinksBackup[i]  := FLinks[i];
    end;
end;

procedure TParsingMenuLeft.RestaureBackup;
var i: integer;
begin
    for i := CNT_MENU_ARRAY_ID_START to CNT_MENU_ARRAY_ID_END do begin
       FLinks[i]  := FLinksBackup[i];
    end;

end;

procedure TParsingMenuLeft.SetFullURLFromBase(const BaseLink: string);
var i: integer;
begin

    for i := CNT_MENU_ARRAY_ID_START to CNT_MENU_ARRAY_ID_END do
       FLinks[i]  := sHTML_Get_URL_Lien(BaseLink, FLinks[i]);

end;

function TParsingMenuLeft.GetLink(IdLink: integer): string;
begin
    Result := '';

    if IdLink > CNT_MENU_ARRAY_ID_END then exit;
    if IdLink < CNT_MENU_ARRAY_ID_START then exit;

    Result := FLinks[IdLink];

end;

function TParsingMenuLeft.GetNbLinkFound: integer;
var i: integer;
begin
    Result := 0;

    for i := CNT_MENU_ARRAY_ID_START to CNT_MENU_ARRAY_ID_END do begin
       if FLinks[i] <> '' then begin
          Inc(Result);
       end;

    end;

end;

procedure TParsingMenuLeft.ScanOnStartTag(Sender: TObject; TagName: string; Attributes: TAttrList);
var CurrBalise: string;
    xPos: integer;
begin

   TagName := lowercase(TagName);

   if TagName = 'a' then begin
      // <a href='overview.php?session=000000' accesskey="u" target='Hauptframe'>Apercu</a>
      FInLink := true;

      CurrBalise := Attributes.Value('target');

      // Tout les liens pointent vers la frame de droite
      if CurrBalise = '' then exit;

      // On pourrait également vérifier l'accesskey
      // Mais on passe directement au lien
      CurrBalise := Attributes.Value('href');

      // overview
      // b_building
      // resources
      // buildings  mode=Forschung
      // buildings.php?session=00000&mode=Flotte
      // flotten1.php?session=00000&mode=Flotte
      // galaxy.php?session=00000
      // buildings.php?session=00000&mode=Verteidigung
      // allianzen.php?session=0000
      // messages.php?session=0000

      FLaskLink := CurrBalise;
      CurrBalise := lowercase(CurrBalise);

      if pos('overview', CurrBalise) > 0 then begin
         FLinks[CNT_MENU_APPERCU] := FLaskLink;

      end else if pos('b_building', CurrBalise) > 0 then begin
         FLinks[CNT_MENU_BATIMENTS] := FLaskLink;

      end else if pos('resources', CurrBalise) > 0 then begin
         FLinks[CNT_MENU_RESSOURCES] := FLaskLink;

      end else if pos('buildings', CurrBalise) > 0 then begin
         xPos := pos('?', CurrBalise);
         if xPos = 0 then exit;
         System.Delete(CurrBalise, 1, xPos);
         
         if pos('forschung', CurrBalise) > 0 then begin
            FLinks[CNT_MENU_RECHERCHES]      := FLaskLink;

         end else if pos('flotte', CurrBalise) > 0 then begin
            FLinks[CNT_MENU_CHANTIERSPATIAL] := FLaskLink;

         end else if pos('verteidigung', CurrBalise) > 0 then begin
            FLinks[CNT_MENU_DEFENSE] := FLaskLink;
         end;

      end else if pos('flotten', CurrBalise) > 0 then begin
         FLinks[CNT_MENU_FLOTTE] := FLaskLink;


      end else if pos('messages', CurrBalise) > 0 then begin
         FLinks[CNT_MENU_MESSAGES] := FLaskLink;

      end else if pos('stat', CurrBalise) > 0 then begin
         FLinks[CNT_MENU_STATISTIQUES] := FLaskLink;


      end else if pos('galaxy', CurrBalise) > 0 then begin
         FLinks[CNT_MENU_GALAXIE] := FLaskLink;


      end else if pos('imperium', CurrBalise) > 0 then begin
         // http://beta.ogame.de/game/imperium.php?session=000000&planettype=1
         FIsCompteCommandant := true;

      end;


   end else if TagName = 'img' then begin
      // FURLToDownloadAsIgnore
      CurrBalise := Attributes.Value('src');

      if pos('gameforge', lowercase(CurrBalise)) > 0 then begin
         FURLToDownloadAsIgnore.Add(CurrBalise);
      end;

   end else if TagName = 'meta' then begin
       CurrBalise := Attributes.Value('http-equiv');

       if SameText('refresh', CurrBalise) then begin
          CurrBalise := Attributes.Value('content');

          // 1800;URL=leftmenu.php?session=0000000000
          xPos := pos(';', CurrBalise);

          if xPos > 0 then begin
             // TODO: Peut-être sauvegarder l'url ??
             System.Delete(CurrBalise, xPos, maxint);

             try
                FDelayRefresh := StrToIntDef(CurrBalise, -1);
             except
                FDelayRefresh := -1;
             end;
          end;
       end; 
   end;


end;

procedure TParsingMenuLeft.ScanOnEndTag(Sender: TObject; TagName: string);
begin
   TagName := lowercase(TagName);

   if TagName = 'a' then begin
       FInLink := false;
   end;

end;

procedure TParsingMenuLeft.ScanOnContent(Sender: TObject; Content: string);
begin
    // Pour de futur amélioration, on calque le lien en fonction de
    // ce qui est affiché, et plus en fonction du nom de la page
end;

function TParsingMenuLeft.ParseBuffer(const Tampon: string): boolean;
var i: integer;
    xTampon: string;
begin
    FError := False;
    FIsCompteCommandant := False;

    for i := CNT_MENU_ARRAY_ID_START to CNT_MENU_ARRAY_ID_END do begin
       FLinksBackup[i] :=  FLinks[i];
       FLinks[i]       := '';
    end;


       FDelayRefresh := -1;
       FURLToDownloadAsIgnore.Clear;

    xTampon := sfcRemplace(Tampon, 'selected', 'selected="1"');
    xTampon := sfcRemplace(xTampon, ' />', '>');
    xTampon := sfcRemplace(xTampon, '"/>', '">');

    xTampon := sfcRemplace(xTampon, '/>', '>');

    FScanner.LoadFromBuffer(PChar(xTampon));
    FScanner.Execute;

    Result := NoT(FError);

    if Result then begin
       // vérifie le nb de liens trouvés
       if GetNbLinkFound < 8 then begin
          // erreur
          Result := false;
       end;
    end;

end;


constructor TParsingMenuLeft.Create;
var i: integer;
begin
    inherited Create;

    FScanner := TEasyXmlScanner.Create(nil);

    FScanner.OnEndTag   := ScanOnEndTag;
    FScanner.OnEmptyTag := nil;
    FScanner.OnStartTag := ScanOnStartTag;
    FScanner.OnContent  := nil; // ScanOnContent;

    FURLToDownloadAsIgnore := TStringList.Create;

    for i := CNT_MENU_ARRAY_ID_START to CNT_MENU_ARRAY_ID_END do begin
       FLinks[i]       := '';
       FLinksBackup[i] := '';
    end;

end;

destructor TParsingMenuLeft.Destroy;
begin
    FURLToDownloadAsIgnore.Free;
    FScanner.Free;
    inherited Destroy;

end;


//////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////



procedure TParsingFrameSet.ScanOnStartTag(Sender: TObject; TagName: string; Attributes: TAttrList);
var CurrBalise: string;
    xPos: integer;
begin

   TagName := lowercase(TagName);

   if TagName = 'frame' then begin
      // leftmenu.php?session=pppppppp
      // overview.php?session=pppppppp&w=0
      
      CurrBalise := Attributes.Value('src');


      if FFrameURLLeft = '' then
         FFrameURLLeft := CurrBalise
      else if FFRameURLRight = '' then begin
         FFRameURLRight := CurrBalise;
         FFrameRightName := Attributes.Value('name');

         FScanner.StopParser := true;
      end;

   end;

end;

function TParsingFrameSet.ParseBuffer(const Tampon: string): boolean;
begin
    FError := false;
    FFrameURLLeft := '';
    FFRameURLRight := '';


    FScanner.LoadFromBuffer(PChar(Tampon));
    FScanner.Execute;

    if FFrameURLLeft = '' then
       FError := true;

    if FFRameURLRight = '' then
       FError := true;

    Result := NoT(FError);
    

end;

constructor TParsingFrameSet.Create;
begin

    inherited Create;

    FScanner := TEasyXmlScanner.Create(nil);

    FScanner.OnEmptyTag := nil;
    FScanner.OnStartTag := ScanOnStartTag;
end;

destructor TParsingFrameSet.Destroy;
begin

    FScanner.Free;
    inherited Destroy;

end;


//////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////


function TParsingAfterLogInPage.ParseBuffer(const Tampon: string): boolean;
begin
    FError := false;
    FURLRedirect := '';

    FScanner.LoadFromBuffer(PChar(Tampon));
    FScanner.Execute;

    if FURLRedirect = '' then
       FError := true;

       
    Result := NoT(FError);

end;

procedure TParsingAfterLogInPage.ScanOnStartTag(Sender: TObject; TagName: string; Attributes: TAttrList);
var CurrBalise: string;
    xPos: integer;
begin

   TagName := lowercase(TagName);

   if TagName = 'meta' then begin
      // 
      CurrBalise := lowercase(Attributes.Value('http-equiv'));

      if CurrBalise = 'refresh' then begin
         // content="0; URL=../../game/index.php?session=0000000000">
         // donc CurrBalise = '0; URL=../../game/index.php?session=000000000000000';
         CurrBalise := Attributes.Value('content');

         xPos := pos('url=', lowercase(CurrBalise));

         if xPos > 0 then begin
            System.Delete(CurrBalise, 1, xPos + 3);

            xPos := pos('"', CurrBalise);
            if xPos > 0 then
               System.Delete(CurrBalise, xPos, maxint);

            xPos := pos(' ', CurrBalise);
            if xPos > 0 then
               System.Delete(CurrBalise, xPos, maxint);


            FURLRedirect := CurrBalise;

         end;

      end;



   end;

end;

constructor TParsingAfterLogInPage.Create;
begin

    inherited Create;

    FScanner := TEasyXmlScanner.Create(nil);

    FScanner.OnEmptyTag := nil;
    FScanner.OnStartTag := ScanOnStartTag;
end;

destructor TParsingAfterLogInPage.Destroy;
begin

    FScanner.Free;
    inherited Destroy;

end;


////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
// Page ressource


procedure TParsingPageRessource.SetURLOfThisPage(Valeur: string);
begin
    inherited SetURLOfThisPage(Valeur);

    // Définit l'url entière du formulaire
    FFormAction  := sHTML_Get_URL_Lien(Valeur, FFormAction);

end;

procedure TParsingPageRessource.InitPointeur;
begin
    FCurrElement.Activite      := -1;
    FCurrElement.prEnergie     := 0;
    FCurrElement.csEnergieUsed := 0;
    FCurrElement.csEnergieAllow := 0;
    FCurrElement.prMetal     := 0;
    FCurrElement.prCristal   := 10;
    FCurrElement.prDeuterium := 0;
    FCurrElement.IdOpt       := '';
    FCurrElement.ActiviteForOptimization := -1;

    FCurrElement.Element    := '';
    FCurrElement.ElementGID := -1;
    FCurrElement.ElementLVL := -1;
end;



function TParsingPageRessource.ParseBuffer(const Tampon: string): boolean;
var xTampon: string;
begin
    Lock;

    inherited ParseBuffer(Tampon);

    FInForm           := false;
    FInTable          := false;
    FCurrTableLigne   := 0;
    FCurrTableColone  := 0;
    FSubmitPostAdd := '';
    FItemsTerminated := false;
    

    if FDontFreeTList then begin
       // On ne libére pas la liste
       FRes.Clear;
    end else begin
       // Sinon on la libére
       FreeTList(FRes);
    end;

    FCurrElement := nil;
    //InitPointeur;

    try
       FScanner.Execute;
    except
       FError := true; 
    end;
    
    if FRes.Count < 1 then
       FError := true;

    if FFormAction = '' then
       FError := true;
       

    Result := NoT(FError);
    Unlock;
    
end;

procedure TParsingPageRessource.ScanOnStartTag(Sender: TObject; TagName: string; Attributes: TAttrList);
var CurrAttrib: string;
    aName : string;
begin

   TagName := lowercase(TagName);

   if TagName = 'form' then begin
      // <form action="resources.php?session=00000000" method="post">
      FInForm := true;
      FFormAction := Attributes.Value('action');
      exit;
   end;

   if FInForm = false then exit;

   if TagName = 'table' then begin
      FInTable := true;
      FCurrTableLigne := 0;
      exit;
   end;

   if FInTable = false then exit;

   if TagName = 'tr' then begin
      Inc(FCurrTableLigne);
      FCurrTableColone := 0;
   end else if (TagName = 'th') or (TagName = 'td') then begin
      Inc(FCurrTableColone);

   end else if TagName = 'select' then begin
      FInSelect := true;
      if FCurrElement <> nil then
         FCurrElement.IdOpt       := Attributes.Value('name')
      else
         FError := true;




   end else if TagName = 'option' then begin
      // <option value="100" selected>
      // MAIS un pré traitement le transforme en:
      // <option value="100" selected="1">
      // Pour qu'il soit identifié par le parseur
      CurrAttrib := Attributes.Value('selected');

      if CurrAttrib = '1' then begin
         CurrAttrib := Attributes.Value('value');
         CurrAttrib := trim(CurrAttrib);

         if FCurrElement <> nil then
            FCurrElement.Activite := StrToIntDef(CurrAttrib, 50)
         else
            FError := true;

      end;

   end else if TagName = 'input' then begin
      // <input type=submit name=action value="Calculer">
      // last1=100&last2=100&last3=100&last4=100&last12=100&action=Calculer

      CurrAttrib := Attributes.Value('type');
      CurrAttrib := lowercase(CurrAttrib);

      if CurrAttrib = 'submit' then begin
         if FSubmitPostAdd <> '' then
            FSubmitPostAdd := FSubmitPostAdd + '&';
            
         FSubmitPostAdd := FSubmitPostAdd + Attributes.Value('name');
         CurrAttrib := Attributes.Value('value');
         FSubmitPostAdd := FSubmitPostAdd + '=' + CurrAttrib;
      end;

   end;



end;

procedure TParsingPageRessource.ScanOnEndTag(Sender: TObject; TagName: string);
begin
    // ATTENTION: 
    // Les </TH> ne sont pas obligatoires.
    if FInForm = false then exit;

    TagName := lowercase(TagName);

    if TagName = 'select' then begin
       FInSelect := false;

    end else if TagName = 'table' then begin
       FScanner.StopParser := true;

       if FCurrElement <> nil then begin
          // Ajoute le dernier élément
          FRes.Add(FCurrElement);
          FCurrElement := nil;
       end;


    end else if TagName = 'form' then begin

       if FItemsTerminated then begin
          // Fin des éléments à scanner
          FScanner.StopParser := true;
       end; 

    end;

end;

procedure TParsingPageRessource.ScanOnContent(Sender: TObject; Content: string);
var xPos: integer;
    sTmp: string;
begin
    if FInTable = false then exit;
    if FInSelect then exit;
    if FItemsTerminated then begin
       exit;
    end;

    // La troisième ligne correspond au revenu de base
    if FCurrTableLigne < 3 then exit;

    Content := trim(Content);
    if Content = '' then exit;
    Content := lowercase(Content);



    case FCurrTableColone of
        1: begin
               // Nom du batiment, et son niveau


               if pos(LangParsing.GetData('ressource_strlw_capici', 'capacit'), Content) > 0 then begin
                  // Fin des éléments à scanner
                  //FScanner.StopParser := true;
                  FItemsTerminated := true;


                  // Ajoute le dernier élément
                  FRes.Add(FCurrElement);
                  FCurrElement := nil;

                  
               end else if pos('(', Content) > 0 then begin
                  if FCurrElement <> nil then begin
                     FCurrElement.Element := Content;
                  end;
               end;


           end;

        2: begin
             if SameText(Content, '&nbsp;') then begin
                // dans la nouvelle version (0.76 du 26 février 2007)
                // ils ont ajouté une colonne 'invisible'...
                Dec(FCurrTableColone);
                exit;
             end;

             if FCurrElement = nil then
                New(FCurrElement)
             else begin
                FRes.Add(FCurrElement);
                New(FCurrElement);
             end;
             InitPointeur;

             Content := sfcRemplace(Content, '.', '');
             FCurrElement.prMetal     := StrToIntDef(Content, 0);
           end;

        3: if FCurrElement = nil then begin
              // Fatal error
              SysUtils.Beep;
              FError := true;
           end else begin
              Content := sfcRemplace(Content, '.', '');
              FCurrElement.prCristal   := StrToIntDef(Content, 0);
           end;

        4: if FCurrElement = nil then begin
              // Fatal error
              SysUtils.Beep;
              FError := true;
           end else begin
              Content := sfcRemplace(Content, '.', '');
              FCurrElement.prDeuterium := StrToIntDef(Content, 0);
           end;

        5: begin
             // Soit une valeur entière, soit
             // une valeur avec fraction: 1125/1162
             Content := sfcRemplace(Content, '.', '');
             
             xPos := pos('/', Content);

             if FCurrElement = nil then begin
                SysUtils.Beep;
                FError := true;
                exit;
             end;

             if xPos = 0 then begin
                 // energie produite
                 FCurrElement.prEnergie := StrToIntDef(Content, 0);

             end else begin
                 sTmp := copy(Content, 1, xPos - 1);
                 System.Delete(Content, 1, xPos);

                 FCurrElement.csEnergieUsed  := StrToIntDef(sTmp, 0);
                 FCurrElement.csEnergieAllow := StrToIntDef(Content, 0);

             end;

          end;
        6: begin
               // select, on ignore

           end;
    end;


end;



constructor TParsingPageRessource.Create(Scanner: TEasyXmlScanner);
begin
    inherited Create(Scanner);

    //FScanner := TEasyXmlScanner.Create(nil);



    FRes     := TList.Create;

    FCurrElement := nil;

    FInTable  := false;
    FInForm   := false;

    FDontFreeTList := true;

    FTypeClass := CLASSTYPE_RESSOURCE;
end;

destructor TParsingPageRessource.Destroy;
begin

    FreeTList(FRes);
    
    FRes.Free;
  //  FScanner.Free;
    inherited Destroy;

end;


////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////

function TParsingLogInPage.ParseBuffer(const Tampon: string): boolean;
var x, y: integer;
    xTampon: string;
begin

    // Première implémentation de la fonction depuis la classe mère
    // Pas d'héritage donc

    inherited ParseBuffer(Tampon);

    FInOption := false;
    FInForm   := false;
    FLastOptionValue := '';
    FError := false;
    FDataToPost := '';
    FURLToPost := '';
    // ' />'


    xTampon := sfcRemplace(Tampon, ' />', '>');
    xTampon := sfcRemplace(xTampon, '"/>', '">');

    FScanner.LoadFromBuffer(PChar(xTampon));
    FScanner.Execute;

    Randomize;
    Result := false;

    if FDataToPost <> '' then begin
      // width="40" height="15"

      if length(FDataToPost) < 15 then begin
         FError := true
      end else begin
      
         if FNoMouseClick = false then begin
            // x et y correspondent à la position du click sur l'image
            // quand on valide le formulaire
            x := 4 + Random(30);     // 35px
            y := 1 + Random(10);     // 11px

            // Rajoute le x et y
            if FInputImageButton = '' then begin
               FDataToPost := FDataToPost + format('&x=%d&y=%d', [x, y]);

            end else begin
               FDataToPost := FDataToPost + format('&%s.x=%d&%s.y=%d', [FInputImageButton, x, FInputImageButton, y]);

            end;

            FError := false;
         end;
      end;

    end else
      FError := true;

    if FURLToPost = '' then begin
       FError := true;
    end;

    Result := NoT(FError);

end;

procedure TParsingLogInPage.ScanOnContent(Sender: TObject; Content: string);
var xPos: integer;
begin
    if FInOption then begin
       xPos := pos('.', Content);

       if xPos = 0 then exit;

       Content := copy(Content, 1, xPos - 1);

       // Premier option à ignorer qui contient "Choisis ton univers..."
       if pos(LangParsing.GetData('login_poslw_ignore_choix', 'choisi'), lowercase(Content)) > 0 then exit;



       //if pos('onner', lowercase(Content)) > 0 then exit;

       try
          xPos := StrToInt(Content);
       except
          xPos := -1;
       end;

       if xPos > 0 then begin
          if xPos = FUnivers then begin
             FServeurUniv := FLastOptionValue;

             if FSpecialLoginWithValidAction then begin
                // erreur
                // on ne devrait pas arriver ici
                // il ne devrait pas y avoir d'univers à sélectionner
                FError := true;
             end;

             // Déduit à partir du code javaScript que l'on ananlyse
             // pas dans ce parseur.
             FURLToPost := 'http://' + FServeurUniv + '/game/reg/login2.php';
             FDataToPost := FDataToPost + FServeurUniv;
          end;

       end;

    end;

end;


procedure TParsingLogInPage.ScanOnEndTag(Sender: TObject; TagName: string);
begin

    if FInForm = false then exit;

    TagName := lowercase(TagName);

    if TagName = 'form' then begin
        // fin de la form
       FScanner.StopParser := true;


    end else if TagName = 'option' then begin
       FInOption := false;

    end else if TagName = 'select' then begin
       FInOption := false;

    end;

end;


procedure TParsingLogInPage.ScanOnStartTag(Sender: TObject; TagName: string; Attributes: TAttrList);
var CurrAttrib: string;
    aName : string;
begin

   TagName := lowercase(TagName);

   if TagName = 'form' then begin
      // <form name="formular" action="" method="POST" onSubmit="changeAction('login');">

      // uni béta:
      // <form name="ogame" method="post" action="login2.php">
      FInForm := true;


      if FSpecialLoginWithValidAction then begin
         FURLToPost := Attributes.Value('action');
      end;

      exit;
   end;

   if FInForm = false then exit;

   if TagName = 'input' then begin
       // <input type="hidden" name="timestamp" value="1110932013">
       // <input tabindex="3" alt="Passwort" type="password" class="eingabe" name="pass" value="">
       // FScanner.StopParser := true;

       CurrAttrib := lowercase(Attributes.Value('type'));
       aName      := Attributes.Value('name');

       if CurrAttrib = 'hidden' then begin
           // Valeur cachée
           if FDataToPost <> '' then
              FDataToPost := FDataToPost + '&';

           CurrAttrib := Attributes.Value('value');
           FDataToPost := FDataToPost +  aName + '=' + CurrAttrib;

       end else if (CurrAttrib = 'password')  then begin
           // Zone de saisie de mot de passe
           if FDataToPost <> '' then
              FDataToPost := FDataToPost + '&';

           FDataToPost := FDataToPost +  aName + '=' + HTTPEncodePHPForParams(FPassword);


       end else if SameText(CurrAttrib, 'image')  then begin
           // image du bouton submit
           // son nom est important
           FInputImageButton := aName;

       end else if (CurrAttrib = '') or (CurrAttrib = 'text') then begin
           // Zone de saisie

           if lowercase(aName) = 'login' then begin
              if FDataToPost <> '' then
                 FDataToPost := FDataToPost + '&';

              FDataToPost := FDataToPost +  aName + '=' + HTTPEncodePHPForParams(FLogin);

           end;

       end;
       



   end else if TagName = 'select' then begin
       // <select tabindex="1" name='Uni' class="eingabe" style="width:100%;">
       aName      := Attributes.Value('name');

       if FDataToPost <> '' then
          FDataToPost := FDataToPost + '&';

       // On ne met pas encore la valeur après le égal
       FDataToPost := FDataToPost +  aName + '=';

   end else if TagName = 'option' then begin
       // <option value="213.239.214.210">1. univers</option>
       FLastOptionValue := Attributes.Value('value');
       FInOption := true;

   end;


end;


constructor TParsingLogInPage.Create(Scanner: TEasyXmlScanner);
var i: integer;
begin
    inherited Create(Scanner);

  //  for i := 1 to MAX_UNIVERS do
  //     FUniversServer[i] := '';

    FUnivers  := -1;
    FInOption := false;
    FInForm   := false;

    FNoMouseClick := false;
    FSpecialLoginWithValidAction := false;
end;

destructor TParsingLogInPage.Destroy;
begin

    // Rien à libérer, à part ce qui est fait dans l'héritage
    
    inherited Destroy;
end;



(*  BACKUP GALAXY ANCIENNE VERSION (avec chiffrage)

// Champ de ruines M:0,K:1.800
procedure TParsingGalaxie.ExtractRuinesInfoFromStr(s: string);
var s2: string;
    xPos: integer;
begin

    s := trim(s);

    // Verification basique
    xPos := pos('ruines', lowercase(s));
    if xPos = 0 then exit;

    xPos := LastDelimiter(' ', s);

    if xPos = 0 then exit;
    System.Delete(s, 1, xPos);


    s := sfcRemplace(s, '.', '');

    // M:0,K:1.800
    s2 := sfcTokenGet(s, 1, ',');
    FCurrentPlanete.Ruines.Metal := sfcTokenGetInt(s2, 2, ':', -1);

    s2 := sfcTokenGet(s, 2, ',');
    FCurrentPlanete.Ruines.Cristal := sfcTokenGetInt(s2, 2, ':', -1);

end;


// Lune S:8831,T:15
procedure TParsingGalaxie.ExtractLuneInfoFromStr(s: string);
var s2: string;
    xPos: integer;
begin

    s := trim(s);

    // Verification basique
    xPos := pos('lune', lowercase(s));
    if xPos = 0 then exit;

    xPos := pos(' ', s);

    if xPos = 0 then exit;
    System.Delete(s, 1, xPos);


    s := sfcRemplace(s, '.', '');
    
    // S:8831,T:15
    s2 := sfcTokenGet(s, 1, ',');
    FCurrentPlanete.Lune.Surface := sfcTokenGetInt(s2, 2, ':', -1);

    s2 := sfcTokenGet(s, 2, ',');
    FCurrentPlanete.Lune.Temperature := sfcTokenGetInt(s2, 2, ':', maxint);


    if FCurrentPlanete.Lune.Temperature = maxint then begin
       // echec, la temperature pouvant etre negative, on se base sur la surface
       // pour s assurer que la lune existe
       FCurrentPlanete.Lune.Surface := -1;

    end;



end;


procedure TParsingGalaxie.InitPlanete;
begin

   
   FCurrentPlanete.Location.Position := -1;

   // Nom de la planète
   FCurrentPlanete.NomPlanete     := '';

   // Nom du joueur
   FCurrentPlanete.Joueur  := '';

   // Alliance du joueur
   FCurrentPlanete.Alliance:= '';


   FCurrentPlanete.Lune.Surface := -1;
   FCurrentPlanete.Lune.Temperature := maxint;

   FCurrentPlanete.Ruines.Metal   := 0;
   FCurrentPlanete.Ruines.Cristal := 0;

   // Il y a jamais de deuterium dans les ruines
   FCurrentPlanete.Ruines.Deuterium := 0;
   FCurrentPlanete.Ruines.Energie   := 0;

   FCurrentPlanete.Position := -1;
   FCurrentPlanete.HaveToBeUpdatedFixed := true;

   FCurrentPlanete.Flags := 0;

end;






procedure TParsingGalaxie.CheckAndAjoutCurrent;
begin

    if FCurrentPlanete.Location.Position > 0 then begin

       if (FCurrentPlanete.Joueur = '') and (FCurrentPlanete.NomPlanete = '') and (FCurrentPlanete.Alliance = '') then begin
          // Planète non colonisée
          sfcFlagsAdd(CNT_GALAXIE_FLAGS_PLANETE_NON_OCCUPEE, FCurrentPlanete.Flags);
       end;

       if FDontAddPointeur = false then
          FListPlanete.Ajout(FCurrentPlanete);

    end;

    // Initialise l element
    InitPlanete;
end;


procedure TParsingGalaxie.ScanOnStartTag(Sender: TObject; TagName: string; Attributes: TAttrList);
var CurrBalise: string;
begin

   TagName := lowercase(TagName);

   if TagName = 'script' then begin
      FInScript := true;


      Inc(FScriptBaliseNum);


   end else if TagName = 'table' then begin
      FInTable := true;
      FTableLigne := 0;
      FTableColonne := 0;

   end else if TagName = 'tr' then begin
      Inc(FTableLigne);
      FTableColonne := 0;


      if FTableLigne > 2 then begin
         // Ajoute l element
         if FCurrentPlanete.Location.Position > 0 then begin

            if (FCurrentPlanete.Joueur = '') and (FCurrentPlanete.NomPlanete = '') and (FCurrentPlanete.Alliance = '') then begin
               // Planète non colonisée
               sfcFlagsAdd(CNT_GALAXIE_FLAGS_PLANETE_NON_OCCUPEE, FCurrentPlanete.Flags);
            end;

            if FDontAddPointeur = false then
               FListPlanete.Ajout(FCurrentPlanete);
         end;

      end;

      // Initialise l element
      InitPlanete;

   end else if (TagName = 'td') or (TagName = 'th') then begin
      Inc(FTableColonne);
      FStateColPlanete := 0;


   end else if TagName = 'font' then begin
      FInFont := true;
      FFontColor := Attributes.Value('color');

   end else if TagName = 'a' then begin
      FInLink := true;

      // On utilise FFullContent
      FFullContent := Attributes.Value('title');

   end;






end;



procedure TParsingGalaxie.TraitementFlags(sFlags: string);
var i, lng: integer;
begin


    lng := length(sFlags);

    for i := 1 to lng do begin

       case sFlags[i] of
           'i': sfcFlagsAdd(CNT_GALAXIE_FLAGS_INACTIF_2SEMAINES, FCurrentPlanete.Flags);
           'I': sfcFlagsAdd(CNT_GALAXIE_FLAGS_INACTIF_4SEMAINES, FCurrentPlanete.Flags);
           'g': sfcFlagsAdd(CNT_GALAXIE_FLAGS_USER_BLOQUE, FCurrentPlanete.Flags);
       end;

    end;


end;

procedure TParsingGalaxie.ScanOnContent(Sender: TObject; Content: string);
var xPos, xPos2: integer;
    sContent: string;
begin

    if FInScript then begin
       FFullContent := FFullContent + ' ' + Content;
    end;


    if NoT(FInTableauGalaxie) then exit;

    if FInTable then begin

        if FTableLigne < 3 then exit;


         case FTableColonne of
             1: begin
                    // Position de la planete <a title="Champ de ruines M:0,K:1.800">T</a>
                    // Taille de la lune <a title="Lune S:8831,T:15">M </a>
                    // Champs de ruine

                    Content := trim(Content);

                    if lowercase(Content) = 't' then begin
                       ExtractRuinesInfoFromStr(FFullContent);
                       exit;

                    end else if lowercase(Content) = 'm' then begin
                       ExtractLuneInfoFromStr(FFullContent);
                       exit;
                    end else if lowercase(Content) = 'a' then begin
                       // astéroide
                       FAllowOneError := true;
                       sfcFlagsAdd(CNT_GALAXIE_FLAGS_ASTEROIDES, FCurrentPlanete.Flags);

                       exit;
                    end;


                    try
                    
                       // Il se peut que la lettre T ou M figure dans la suite
                       if FCurrentPlanete.Location.Position < 0 then
                          FCurrentPlanete.Location.Position := StrToInt(Content);

                    except
                       FCurrentPlanete.Location.Position := -1;
                    end;

                end;

             2: begin
                    // Alliance, nom de la planete et du joueur
                    if FInFont and FInLink then begin
                       // Alliance

                       // Dans le cas de font et de balise a activent, on sait obligatoirement
                       // que l'on est dans le cas de l'alliance, on ne touche donc
                       // pas à FStateColPlanete
                       

                       // supprime les []
                       xPos := pos('[', Content);
                       if xPos > 0 then
                         System.Delete(Content, xPos, 1);

                       xPos := LastDelimiter(']', Content);
                       if xPos > 0 then
                         System.Delete(Content, xPos, 1);

                       FCurrentPlanete.Alliance := trim(Content);

                       
                    end else begin
                       //  protection des noob:
                       // planetName ( <font color=a0ffa0>Nick<font color=#ffffff> )
                       // Il y a des balises font dans ce cas la

                       // Mode vacances avec iI
                       //<font color= 00ff00>[SVS]</font></a> planetName ( <font color=#0000ff>Nick</font>(iI) )


                       // Joueur et planete
                       // Acropolis ( Laskov )
                       // Ankhou ( king_nico(i) )

                       // Au cas où se serai un cas spécial (bloqué, mode vacance, inactif)
                       Inc(FStateColPlanete);


                       case FStateColPlanete of
                           1: begin
                                   // Premier passage (sans compter l'alliance)

                                   // Les parenthèses sont interdites dans le nom de la planète
                                   // On extrait directement le nom de la planète, il existe obligatoirement
                                   xPos := pos('(', Content);
                                   if xPos = 0 then begin
                                      if FAllowOneError = false then
                                         FError := true
                                      else
                                         FAllowOneError := false;

                                      exit;
                                   end;

                                   // Extrait le nom de la planète
                                   FCurrentPlanete.NomPlanete := trim(copy(Content, 1, xPos - 1));

                                   // Supprime le nom de la planète
                                   System.Delete(Content, 1, xPos);
                                   Content := trimleft(Content);

                                   // Maintenant, il se peut que l'on rencontre une balise font
                                   // pour un joueur noob/trop fort/en vacance
                                   // Exemple:     planetName ( <font color=#0000ff>Nick</font>(iI) )
                                   // les flags (bloqué, inactif), sont toujours à l'extérieur de la balise font

                                   // Si il y a pas de balises fonts, alors
                                   // La chaine originale "planetName ( Nick(i) )"
                                   // est devenu          " Nick(i) )"

                                   xPos := pos(')', Content);
                                   if xPos = 0 then begin
                                      // il doit avoir une balise font
                                      exit;
                                   end;

                                   // On va supposer que les parenthèses sont interdites dans le nom du joueur
                                   xPos2 := pos('(', Content);
                                   if xPos2 > 0 then begin
                                      // Il existe des flags (iIg)
                                      FCurrentPlanete.Joueur := trim(copy(Content, 1, xPos2 - 1));

                                      System.Delete(Content, 1, xPos2);

                                      xPos := pos(')', Content);
                                      if xPos > 0 then begin
                                         System.Delete(Content, xPos, maxint);

                                         // Il ne reste plus que les flags dans Content
                                         TraitementFlags(Content);

                                      end;

                                   end else begin
                                      // pas de flags, il ne reste donc que le nom du joueur
                                      FCurrentPlanete.Joueur := trim(copy(Content, 1, xPos - 1));
                                   end;

                              end;


                           2: begin
                                   // On est alors forcément dans une balise font
                                   // Le contenu  entier correspond au nom du joueur
                                   FCurrentPlanete.Joueur := trim(Content);

                                   // On utilise FFontColor pour savoir quel type de flag cela correspond
                                   // FFontColor
                                   // <font color=#ffa0a0>joueur fort
                                   // <font color=#a0ffa0>joueur faible
                                   // <font color=#0000ff>Mode vacances

                                   FFontColor := trim(FFontColor);

                                   if FFontColor <> '' then begin
                                      // Dans le code de la page, les couleurs sont sans #
                                      if FFontColor[1] = '#' then
                                         System.Delete(FFontColor, 1, 1);

                                      FFontColor := lowercase(FFontColor);
                                      sContent := copy(FFontColor, 1, 5);

                                      if SameText(sContent, 'ffa0a') then begin
                                          // joueur fort
                                          sfcFlagsAdd(CNT_GALAXIE_FLAGS_PROTECTION_NOOB_TROPFORT, FCurrentPlanete.Flags);

                                      end else if SameText(sContent, 'a0ffa') then begin
                                          // joueur faible
                                          sfcFlagsAdd(CNT_GALAXIE_FLAGS_PROTECTION_NOOB_TROPFAIBLE, FCurrentPlanete.Flags);

                                      end else if SameText(FFontColor, '0000ff') then begin
                                          // Mode vacances
                                          sfcFlagsAdd(CNT_GALAXIE_FLAGS_MODE_VACANCES, FCurrentPlanete.Flags);

                                      end;

                                   end;


                              end;

                           3: begin
                                   // La balise font vient de se terminer, il reste les flags
                                   // et la parenthèse de fin
                                   // planetName ( <font color=#0000ff>nick</font>(iI) )
                                   // Exemple: (iI) )
                                   // ou encore la parenthèse de fin toute seule

                                   xPos := pos('(', Content);
                                   if xPos > 0 then begin
                                      // il existe des flags, on les traite
                                      System.Delete(Content, 1, xPos);

                                      xPos := pos(')', Content);
                                      if xPos > 0 then begin
                                         System.Delete(Content, xPos, maxint);

                                         TraitementFlags(Content);
                                      end;

                                   end;

                              end;

                       end;


                    end;

                end;

             3: begin


                end;

         end;


    end;


end;



procedure TParsingGalaxie.ScanOnEndTag(Sender: TObject; TagName: string);
begin
   TagName := lowercase(TagName);

   if TagName = 'script' then begin
      FInScript := false;

      if pos('wrt(', FFullContent) > 0 then begin
         // balise de script
         Inc(FScriptBaliseNum);

         TraitementPremiereBaliseScript;

         if FSystemSolaire > 0 then begin
            FScanner.StopParser := true;
         end;


      end;

      FFullContent := '';


      // Ajoute l element, et le réinitialise
      CheckAndAjoutCurrent;


   end else if TagName = 'tr' then begin
      // La balise de fin de ligne n existe pas

   end else if TagName = 'font' then begin
      FInFont := false;
      FFontColor := '';

   end else if TagName = 'a' then begin
      FInLink := false;

   end;



end;





function TParsingGalaxie.ParseBuffer(const Tampon: string): boolean;
var sBuffer: string;
    xPos: integer;
begin
    inherited ParseBuffer(Tampon);

    FInScript := false;
    FScriptBaliseNum := 0;
    FListPlanete.Clear;

    FGalaxie       := -1;
    FSystemSolaire := -1;
    FSessionKey    := '';

    FInTableauGalaxie := false;
    FInLink := false;

    InitPlanete;
    FError := false;
    FAllowOneError := false;


    // Charge le tampon
    FScanner.LoadFromBuffer(PChar(Tampon));
    FScanner.Execute;


    if FError then begin
       Result := false;
       exit;
    end;


    // maintenant parsing le tableau
    // parsing a la main
    xPos := pos('wrtg("', Tampon);
    if xPos > 0 then begin
       sBuffer := copy(Tampon, xPos + 6, maxint);


       FFullContent := '';
       FFontColor   := '';

       FListPlanete.Clear;

       FInTableauGalaxie := true;

       // Decrypte la chaine
       GetReal(sBuffer);


       sBuffer := '<table width=470> <tr> <td class=c colspan=3>Système solair p1:p2 </td></tr> <tr> <th>Planète</th> <th>Nom</th> <th>Action</th> </tr>' + sBuffer;
       sBuffer := sBuffer + '</body> </html>';


       // initialisation pour le second parsing
       FInTable     := false;
       FTableLigne  := -1;
       FTableColonne:= -1;
       FInFont := false;

       FInScript  := false;
       FScriptBaliseNum := 0;

       FInFont := false;
       FInLink := false;
       FStateColPlanete := -1;


       sBuffer := sfcRemplace(sBuffer, '\"', '"');

       //DebugWebPage(sBuffer);

       // Champs fixe
       FCurrentPlanete.Location.Galaxie       := FGalaxie;
       FCurrentPlanete.Location.SystemSolaire := FSystemSolaire;
       FCurrentPlanete.Date := DateTimetoUnix(Now);

       InitPlanete;
       FAllowOneError := false;


       // Charge le tampon
       FScanner.LoadFromBuffer(PChar(sBuffer));
       FScanner.Execute;



    end else begin
       // Renvoi True quand on a échoué
       // car FError est à true quand il y a une erreur, et on renvoi
       // NoT(FError)
       Result := false;
       exit;
    end;


    FFullContent := '';
    FFontColor   := '';

    Result := NoT(FError);

end;


procedure TParsingGalaxie.TraitementPremiereBaliseScript;
var s: string;
begin

    // FFullContent
    // wrt("50f7ea1d9486",2,309);

    s := sfcTokenGet(FFullContent, 2, '(');
    s := sfcTokenGet(s, 1, ')');

    FSessionKey    := sfcTokenGet(s, 1, ',');
    FGalaxie       := sfcTokenGetInt(s, 2, ',', -1);
    FSystemSolaire := sfcTokenGetInt(s, 3, ',', -1);

    // supprime les "" de FSessionKey
    FSessionKey := sfcRemplace(FSessionKey, '"', '');

end;

constructor TParsingGalaxie.Create(Scanner: TEasyXmlScanner);
begin
   inherited Create(Scanner);


   FListPlanete := TListGalaxiePlaneteSP.Create;
   FDontAddPointeur := false;
end;


destructor TParsingGalaxie.Destroy;
begin

   FListPlanete.Free;

   inherited Destroy;
end;


//procedure TParsingGalaxie.TraitementSecondeBaliseScript;
//begin
    // wrt2("50f7ea1d9486",2,309);

//end;



procedure GetReal(var str: string);
begin

//s=s.replace(/#1/g,'<tr><th>');
//s=s.replace(/#2/g,'</th><th>');
//s=s.replace(/#3/g,'</th>');


   str := sfcRemplace(str, '#1', '<tr><th>');
   str := sfcRemplace(str, '#2', '</th><th>');
   str := sfcRemplace(str, '#3', '</th>');


//s=s.replace(/#8/g,'<th> <a href=\"flotten.php?session=' + ss + '&fstate=3&type=Espionage&gesver2=1&ladekap2=5&s=10&c210='+a+'&ft1='+p1+'&ft2='+p2+'&ft3=');
//s=s.replace(/#9/g,'\"><img src=\"http://serveur/ogame/game/img/e.gif\" border=0 alt=\"'+a+' Envoyer la sonde\">    </a>');
//s=s.replace(/#b/g,'<a href=\"galaxy.php?session=' + ss + '&mode=1&p1='+p1+'&p2='+p2+'&ft3=');
//s=s.replace(/#c/g,'\"><img src=\"http://ogame.org/ogame/game/img/r.gif\" border=0 alt=\"Attaque de missile\">    </a>');


   str := sfcRemplace(str, '#8', '<th> <a href="flotten.php?session=<sessionkey>&fstate=3&type=Espionage&gesver2=1&ladekap2=5&s=10&c210=<param_a>&ft1=<param_p1>&ft2=<param_p2>&ft3=');
   str := sfcRemplace(str, '#9', '"><img src="http://serveur/ogame/game/img/e.gif" border=0 alt="<param_a> Envoyer la sonde"> </a>');
   str := sfcRemplace(str, '#b', '<a href="galaxy.php?session=<sessionkey>&mode=1&p1=<param_p1>&p2=<param_p2>&ft3=');
   str := sfcRemplace(str, '#c', '"><img src="http://ogame.org/ogame/game/img/r.gif" border=0 alt="Attaque de missile">  </a>');


//s=s.replace(/#4/g,'<a href=\"writemessages.php?session=' + ss + '&messageziel=');
//s=s.replace(/#5/g,'\"><img src=\"http://serveur/ogame/game/img/m.gif\" border=0 alt=\"Ecrire un message\"></a><a href=\"buddy.php?session=' + ss + '&a=2&u=');
//s=s.replace(/#X/g,'\"><img src=\"http://serveur/ogame/game/img/b.gif\" border=0 alt=\"Demande de pote\"></a>');


   str := sfcRemplace(str, '#4', '<a href="writemessages.php?session=<sessionkey>&messageziel=');
   str := sfcRemplace(str, '#5', '"><img src="http://serveur/ogame/game/img/m.gif" border=0 alt="Ecrire un message"></a><a href="buddy.php?session=<sessionkey>&a=2&u=');
   str := sfcRemplace(str, '#X', '"><img src="http://serveur/ogame/game/img/b.gif" border=0 alt="Demande de pote"></a>');


//s=s.replace(/#6/g,'</th>');
//s=s.replace(/#7/g,'<th>');
//s=s.replace(/#a/g,'</th><th></th>');

   str := sfcRemplace(str, '#6', '</th>');
   str := sfcRemplace(str, '#7', '<th>');
   str := sfcRemplace(str, '#a', '</th><th></th>');


end;

*)

end.

